Beispiel #1
0
static inline void truncate (struct inode * inode)
{
	struct super_block *sb = inode->i_sb;
	block_t *idata = i_data(inode);
	int offsets[DEPTH];
	Indirect chain[DEPTH];
	Indirect *partial;
	block_t nr = 0;
	int n;
	int first_whole;
	long iblock;

	iblock = (inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits;
	block_truncate_page(inode->i_mapping, inode->i_size, get_block);

	n = block_to_path(inode, iblock, offsets);
	if (!n)
		return;

	if (n == 1) {
		free_data(inode, idata+offsets[0], idata + DIRECT);
		first_whole = 0;
		goto do_indirects;
	}

	first_whole = offsets[0] + 1 - DIRECT;
	partial = find_shared(inode, n, offsets, chain, &nr);
	if (nr) {
		if (partial == chain)
			mark_inode_dirty(inode);
		else
			mark_buffer_dirty_inode(partial->bh, inode);
		free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
	}
	/* Clear the ends of indirect blocks on the shared branch */
	while (partial > chain) {
		free_branches(inode, partial->p + 1, block_end(partial->bh),
				(chain+n-1) - partial);
		mark_buffer_dirty_inode(partial->bh, inode);
		brelse (partial->bh);
		partial--;
	}
do_indirects:
	/* Kill the remaining (whole) subtrees */
	while (first_whole < DEPTH-1) {
		nr = idata[DIRECT+first_whole];
		if (nr) {
			idata[DIRECT+first_whole] = 0;
			mark_inode_dirty(inode);
			free_branches(inode, &nr, &nr+1, first_whole+1);
		}
		first_whole++;
	}
	inode->i_mtime = inode->i_ctime = current_time(inode);
	mark_inode_dirty(inode);
}
Beispiel #2
0
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
				 handle_t *handle, struct inode *inode,
				 struct buffer_head *bh)
{
	int err = 0;

	if (ext4_handle_valid(handle)) {
		err = jbd2_journal_dirty_metadata(handle, bh);
		if (err) {
			/* Errors can only happen if there is a bug */
			handle->h_err = err;
			__ext4_journal_stop(where, line, handle);
		}
	} else {
		if (inode)
			mark_buffer_dirty_inode(bh, inode);
		else
			mark_buffer_dirty(bh);
		if (inode && inode_needs_sync(inode)) {
			sync_dirty_buffer(bh);
			if (buffer_req(bh) && !buffer_uptodate(bh)) {
				struct ext4_super_block *es;

				es = EXT4_SB(inode->i_sb)->s_es;
				es->s_last_error_block =
					cpu_to_le64(bh->b_blocknr);
				ext4_error_inode(inode, where, line,
						 bh->b_blocknr,
					"IO error syncing itable block");
				err = -EIO;
			}
		}
	}
	return err;
}
Beispiel #3
0
static inline void dirty_indirect(struct buffer_head *bh, struct inode *inode)
{
	mark_buffer_dirty_inode(bh, inode);
	if (IS_SYNC(inode)) {
		ll_rw_block (WRITE, 1, &bh);
		wait_on_buffer (bh);
	}
}
Beispiel #4
0
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
                                 handle_t *handle, struct inode *inode,
                                 struct buffer_head *bh)
{
    int err = 0;

    might_sleep();

    set_buffer_meta(bh);
    set_buffer_prio(bh);
    if (ext4_handle_valid(handle)) {
        err = jbd2_journal_dirty_metadata(handle, bh);
        /* Errors can only happen if there is a bug */
        if (WARN_ON_ONCE(err)) {
            ext4_journal_abort_handle(where, line, __func__, bh,
                                      handle, err);
            if (inode == NULL) {
                pr_err("EXT4: jbd2_journal_dirty_metadata "
                       "failed: handle type %u started at "
                       "line %u, credits %u/%u, errcode %d",
                       handle->h_type,
                       handle->h_line_no,
                       handle->h_requested_credits,
                       handle->h_buffer_credits, err);
                return err;
            }
            ext4_error_inode(inode, where, line,
                             bh->b_blocknr,
                             "journal_dirty_metadata failed: "
                             "handle type %u started at line %u, "
                             "credits %u/%u, errcode %d",
                             handle->h_type,
                             handle->h_line_no,
                             handle->h_requested_credits,
                             handle->h_buffer_credits, err);
        }
    } else {
        if (inode)
            mark_buffer_dirty_inode(bh, inode);
        else
            mark_buffer_dirty(bh);
        if (inode && inode_needs_sync(inode)) {
            sync_dirty_buffer(bh);
            if (buffer_req(bh) && !buffer_uptodate(bh)) {
                struct ext4_super_block *es;

                es = EXT4_SB(inode->i_sb)->s_es;
                es->s_last_error_block =
                    cpu_to_le64(bh->b_blocknr);
                ext4_error_inode(inode, where, line,
                                 bh->b_blocknr,
                                 "IO error syncing itable block");
                err = -EIO;
            }
        }
    }
    return err;
}
Beispiel #5
0
struct inode *
affs_new_inode(struct inode *dir)
{
    struct super_block	*sb = dir->i_sb;
    struct inode		*inode;
    u32			 block;
    struct buffer_head	*bh;

    if (!(inode = new_inode(sb)))
        goto err_inode;

    if (!(block = affs_alloc_block(dir, dir->i_ino)))
        goto err_block;

    bh = affs_getzeroblk(sb, block);
    if (!bh)
        goto err_bh;
    mark_buffer_dirty_inode(bh, inode);
    affs_brelse(bh);

    inode->i_uid     = current_fsuid();
    inode->i_gid     = current_fsgid();
    inode->i_ino     = block;
    inode->i_nlink   = 1;
    inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
    atomic_set(&AFFS_I(inode)->i_opencnt, 0);
    AFFS_I(inode)->i_blkcnt = 0;
    AFFS_I(inode)->i_lc = NULL;
    AFFS_I(inode)->i_lc_size = 0;
    AFFS_I(inode)->i_lc_shift = 0;
    AFFS_I(inode)->i_lc_mask = 0;
    AFFS_I(inode)->i_ac = NULL;
    AFFS_I(inode)->i_ext_bh = NULL;
    AFFS_I(inode)->mmu_private = 0;
    AFFS_I(inode)->i_protect = 0;
    AFFS_I(inode)->i_lastalloc = 0;
    AFFS_I(inode)->i_pa_cnt = 0;
    AFFS_I(inode)->i_extcnt = 1;
    AFFS_I(inode)->i_ext_last = ~1;

    insert_inode_hash(inode);

    return inode;

err_bh:
    affs_free_block(sb, block);
err_block:
    iput(inode);
err_inode:
    return NULL;
}
Beispiel #6
0
int __ext4bf_handle_dirty_metadata(const char *where, unsigned int line,
				 handle_t *handle, struct inode *inode,
				 struct buffer_head *bh)
{
	int err = 0;

	if (ext4bf_handle_valid(handle)) {

#ifdef DCHECKSUM
        /* ext4bf: handle cases where it is a data block. */
        if (bh && bh->b_blocktype == B_BLOCKTYPE_DATA) {
#endif
#ifdef PARTJ
            if (!buffer_new(bh))
                err = jbdbf_journal_dirty_metadata(handle, bh);
            else
#endif
#ifdef DCHECKSUM

                jbdbf_journal_dirty_data(handle, bh);
        } else
#endif
            err = jbdbf_journal_dirty_metadata(handle, bh);
        if (err) {
            /* Errors can only happen if there is a bug */
            handle->h_err = err;
			__ext4bf_journal_stop(where, line, handle);
		}
	} else {
		if (inode)
			mark_buffer_dirty_inode(bh, inode);
		else
			mark_buffer_dirty(bh);
		if (inode && inode_needs_sync(inode)) {
			sync_dirty_buffer(bh);
			if (buffer_req(bh) && !buffer_uptodate(bh)) {
				struct ext4bf_super_block *es;

				es = EXT4_SB(inode->i_sb)->s_es;
				es->s_last_error_block =
					cpu_to_le64(bh->b_blocknr);
				ext4bf_error_inode(inode, where, line,
						 bh->b_blocknr,
					"IO error syncing itable block");
				err = -EIO;
			}
		}
	}
	return err;
}
Beispiel #7
0
int
affs_rename(struct inode *old_dir, struct dentry *old_dentry,
	    struct inode *new_dir, struct dentry *new_dentry)
{
	struct super_block *sb = old_dir->i_sb;
	struct buffer_head *bh = NULL;
	int retval;

	pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
		 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);

	retval = affs_check_name(new_dentry->d_name.name,
				 new_dentry->d_name.len,
				 affs_nofilenametruncate(old_dentry));

	if (retval)
		return retval;

	/* Unlink destination if it already exists */
	if (new_dentry->d_inode) {
		retval = affs_remove_header(new_dentry);
		if (retval)
			return retval;
	}

	bh = affs_bread(sb, old_dentry->d_inode->i_ino);
	if (!bh)
		return -EIO;

	/* Remove header from its parent directory. */
	affs_lock_dir(old_dir);
	retval = affs_remove_hash(old_dir, bh);
	affs_unlock_dir(old_dir);
	if (retval)
		goto done;

	/* And insert it into the new directory with the new name. */
	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
	affs_fix_checksum(sb, bh);
	affs_lock_dir(new_dir);
	retval = affs_insert_hash(new_dir, bh);
	affs_unlock_dir(new_dir);
	/* TODO: move it back to old_dir, if error? */

done:
	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
	affs_brelse(bh);
	return retval;
}
Beispiel #8
0
int
affs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
	struct super_block	*sb = inode->i_sb;
	struct buffer_head	*bh;
	struct affs_tail	*tail;
	uid_t			 uid;
	gid_t			 gid;

	pr_debug("write_inode(%lu)\n", inode->i_ino);

	if (!inode->i_nlink)
		// possibly free block
		return 0;
	bh = affs_bread(sb, inode->i_ino);
	if (!bh) {
		affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
		return -EIO;
	}
	tail = AFFS_TAIL(sb, bh);
	if (tail->stype == cpu_to_be32(ST_ROOT)) {
		affs_secs_to_datestamp(inode->i_mtime.tv_sec,
				       &AFFS_ROOT_TAIL(sb, bh)->root_change);
	} else {
		tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
		tail->size = cpu_to_be32(inode->i_size);
		affs_secs_to_datestamp(inode->i_mtime.tv_sec, &tail->change);
		if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) {
			uid = i_uid_read(inode);
			gid = i_gid_read(inode);
			if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_MUFS)) {
				if (uid == 0 || uid == 0xFFFF)
					uid = uid ^ ~0;
				if (gid == 0 || gid == 0xFFFF)
					gid = gid ^ ~0;
			}
			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETUID))
				tail->uid = cpu_to_be16(uid);
			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETGID))
				tail->gid = cpu_to_be16(gid);
		}
	}
	affs_fix_checksum(sb, bh);
	mark_buffer_dirty_inode(bh, inode);
	affs_brelse(bh);
	affs_free_prealloc(inode);
	return 0;
}
Beispiel #9
0
int
affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
{
    struct super_block *sb;
    struct buffer_head *bh;
    u32 rem_ino, hash_ino;
    __be32 ino;
    int offset, retval;

    sb = dir->i_sb;
    rem_ino = rem_bh->b_blocknr;
    offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
    pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);

    bh = affs_bread(sb, dir->i_ino);
    if (!bh)
        return -EIO;

    retval = -ENOENT;
    hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
    while (hash_ino) {
        if (hash_ino == rem_ino) {
            ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
            if (dir->i_ino == bh->b_blocknr)
                AFFS_HEAD(bh)->table[offset] = ino;
            else
                AFFS_TAIL(sb, bh)->hash_chain = ino;
            affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
            mark_buffer_dirty_inode(bh, dir);
            AFFS_TAIL(sb, rem_bh)->parent = 0;
            retval = 0;
            break;
        }
        affs_brelse(bh);
        bh = affs_bread(sb, hash_ino);
        if (!bh)
            return -EIO;
        hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
    }

    affs_brelse(bh);

    dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
    dir->i_version++;
    mark_inode_dirty(dir);

    return retval;
}
Beispiel #10
0
int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
{
	struct buffer_head *bh;
	struct qnx4_inode_entry *de;
	struct inode *inode;
	int retval;
	int ino;

	QNX4DEBUG(("qnx4: qnx4_rmdir [%s]\n", dentry->d_name.name));
	lock_kernel();
	bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
			     &de, &ino);
	if (bh == NULL) {
		unlock_kernel();
		return -ENOENT;
	}
	inode = dentry->d_inode;
	if (inode->i_ino != ino) {
		retval = -EIO;
		goto end_rmdir;
	}
#if 0
	if (!empty_dir(inode)) {
		retval = -ENOTEMPTY;
		goto end_rmdir;
	}
#endif
	if (inode->i_nlink != 2) {
		QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink));
	}
	QNX4DEBUG(("qnx4: deleting directory\n"));
	de->di_status = 0;
	memset(de->di_fname, 0, sizeof de->di_fname);
	de->di_mode = 0;
	mark_buffer_dirty_inode(bh, dir);
	clear_nlink(inode);
	mark_inode_dirty(inode);
	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
	inode_dec_link_count(dir);
	retval = 0;

      end_rmdir:
	brelse(bh);

	unlock_kernel();
	return retval;
}
Beispiel #11
0
int
affs_insert_hash(struct inode *dir, struct buffer_head *bh)
{
    struct super_block *sb = dir->i_sb;
    struct buffer_head *dir_bh;
    u32 ino, hash_ino;
    int offset;

    ino = bh->b_blocknr;
    offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);

    pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);

    dir_bh = affs_bread(sb, dir->i_ino);
    if (!dir_bh)
        return -EIO;

    hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
    while (hash_ino) {
        affs_brelse(dir_bh);
        dir_bh = affs_bread(sb, hash_ino);
        if (!dir_bh)
            return -EIO;
        hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
    }
    AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
    AFFS_TAIL(sb, bh)->hash_chain = 0;
    affs_fix_checksum(sb, bh);

    if (dir->i_ino == dir_bh->b_blocknr)
        AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
    else
        AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);

    affs_adjust_checksum(dir_bh, ino);
    mark_buffer_dirty_inode(dir_bh, dir);
    affs_brelse(dir_bh);

    dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
    dir->i_version++;
    mark_inode_dirty(dir);

    return 0;
}
Beispiel #12
0
int qnx4_unlink(struct inode *dir, struct dentry *dentry)
{
	struct buffer_head *bh;
	struct qnx4_inode_entry *de;
	struct inode *inode;
	int retval;
	int ino;

	QNX4DEBUG(("qnx4: qnx4_unlink [%s]\n", dentry->d_name.name));
	lock_kernel();
	bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
			     &de, &ino);
	if (bh == NULL) {
		unlock_kernel();
		return -ENOENT;
	}
	inode = dentry->d_inode;
	if (inode->i_ino != ino) {
		retval = -EIO;
		goto end_unlink;
	}
	retval = -EPERM;
	if (!inode->i_nlink) {
		QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n",
			   inode->i_sb->s_id,
			   inode->i_ino, inode->i_nlink));
		inode->i_nlink = 1;
	}
	de->di_status = 0;
	memset(de->di_fname, 0, sizeof de->di_fname);
	de->di_mode = 0;
	mark_buffer_dirty_inode(bh, dir);
	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
	mark_inode_dirty(dir);
	inode->i_ctime = dir->i_ctime;
	inode_dec_link_count(inode);
	retval = 0;

end_unlink:
	unlock_kernel();
	brelse(bh);

	return retval;
}
Beispiel #13
0
static int alloc_branch(struct inode *inode,
			     int num,
			     int *offsets,
			     Indirect *branch)
{
	int n = 0;
	int i;
	int parent = minix_new_block(inode);
	printk("parent new block %d\n",parent);

	branch[0].key = cpu_to_block(parent);
	if (parent) for (n = 1; n < num; n++) {
		struct buffer_head *bh;
		/* Allocate the next block */
		int nr = minix_new_block(inode);
		printk("loop new block %d",nr);
		if (!nr)
			break;
		branch[n].key = cpu_to_block(nr);
		bh = sb_getblk(inode->i_sb, parent);
		lock_buffer(bh);
		memset(bh->b_data, 0, bh->b_size);
		branch[n].bh = bh;
		branch[n].p = (block_t*) bh->b_data + offsets[n];
		*branch[n].p = branch[n].key;
		set_buffer_uptodate(bh);
		unlock_buffer(bh);
		mark_buffer_dirty_inode(bh, inode);
		parent = nr;
	}
	if (n == num)
		return 0;

	/* Allocation failed, free what we already allocated */
	for (i = 1; i < n; i++)
		bforget(branch[i].bh);
	for (i = 0; i < n; i++)
		minix_free_block(inode, block_to_cpu(branch[i].key));
	return -ENOSPC;
}
Beispiel #14
0
static inline int splice_branch(struct inode *inode,
                                Indirect chain[DEPTH],
                                Indirect *where,
                                int num)
{
    int i;

    /* Verify that place we are splicing to is still there and vacant */

    /* Writer: pointers */
    if (!verify_chain(chain, where-1) || *where->p)
        /* Writer: end */
        goto changed;

    /* That's it */

    *where->p = where->key;

    /* Writer: end */

    /* We are done with atomic stuff, now do the rest of housekeeping */

    inode->i_ctime = CURRENT_TIME;

    /* had we spliced it onto indirect block? */
    if (where->bh)
        mark_buffer_dirty_inode(where->bh, inode);

    mark_inode_dirty(inode);
    return 0;

changed:
    for (i = 1; i < num; i++)
        bforget(where[i].bh);
    for (i = 0; i < num; i++)
        minix_free_block(inode, block_to_cpu(where[i].key));
    return -EAGAIN;
}
static inline int splice_branch(struct inode *inode,
				     Indirect chain[DEPTH],
				     Indirect *where,
				     int num)
{
	int i;

	write_lock(&pointers_lock);

	/*                                                                */
	if (!verify_chain(chain, where-1) || *where->p)
		goto changed;

	*where->p = where->key;

	write_unlock(&pointers_lock);

	/*                                                                */

	inode->i_ctime = CURRENT_TIME_SEC;

	/*                                        */
	if (where->bh)
		mark_buffer_dirty_inode(where->bh, inode);

	mark_inode_dirty(inode);
	return 0;

changed:
	write_unlock(&pointers_lock);
	for (i = 1; i < num; i++)
		bforget(where[i].bh);
	for (i = 0; i < num; i++)
		minix_free_block(inode, block_to_cpu(where[i].key));
	return -EAGAIN;
}
Beispiel #16
0
static inline int splice_branch(struct inode *inode,
				     Indirect chain[DEPTH],
				     Indirect *where,
				     int num)
{
	int i;

	write_lock(&pointers_lock);

	/* Verify that place we are splicing to is still there and vacant */
	if (!verify_chain(chain, where-1) || *where->p)
		goto changed;

	*where->p = where->key;

	write_unlock(&pointers_lock);

	/* We are done with atomic stuff, now do the rest of housekeeping */

	inode->i_ctime = current_time(inode);

	/* had we spliced it onto indirect block? */
	if (where->bh)
		mark_buffer_dirty_inode(where->bh, inode);

	mark_inode_dirty(inode);
	return 0;

changed:
	write_unlock(&pointers_lock);
	for (i = 1; i < num; i++)
		bforget(where[i].bh);
	for (i = 0; i < num; i++)
		xiafs_free_block(inode, block_to_cpu(where[i].key));
	return -EAGAIN;
}
static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
			   struct dentry *old_dentry,
			   struct inode *new_dir, unsigned char *new_name,
			   struct dentry *new_dentry, int is_hid)
{
	struct buffer_head *dotdot_bh;
	struct msdos_dir_entry *dotdot_de;
	struct inode *old_inode, *new_inode;
	struct fat_slot_info old_sinfo, sinfo;
	struct timespec ts;
	loff_t dotdot_i_pos, new_i_pos;
	int err, old_attrs, is_dir, update_dotdot, corrupt = 0;

	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
	old_inode = old_dentry->d_inode;
	new_inode = new_dentry->d_inode;

	err = fat_scan(old_dir, old_name, &old_sinfo);
	if (err) {
		err = -EIO;
		goto out;
	}

	is_dir = S_ISDIR(old_inode->i_mode);
	update_dotdot = (is_dir && old_dir != new_dir);
	if (update_dotdot) {
		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
					 &dotdot_i_pos) < 0) {
			err = -EIO;
			goto out;
		}
	}

	old_attrs = MSDOS_I(old_inode)->i_attrs;
	err = fat_scan(new_dir, new_name, &sinfo);
	if (!err) {
		if (!new_inode) {
			
			if (sinfo.de != old_sinfo.de) {
				err = -EINVAL;
				goto out;
			}
			if (is_hid)
				MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
			else
				MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
			if (IS_DIRSYNC(old_dir)) {
				err = fat_sync_inode(old_inode);
				if (err) {
					MSDOS_I(old_inode)->i_attrs = old_attrs;
					goto out;
				}
			} else
				mark_inode_dirty(old_inode);

			old_dir->i_version++;
			old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
			if (IS_DIRSYNC(old_dir))
				(void)fat_sync_inode(old_dir);
			else
				mark_inode_dirty(old_dir);
			goto out;
		}
	}

	ts = CURRENT_TIME_SEC;
	if (new_inode) {
		if (err)
			goto out;
		if (is_dir) {
			err = fat_dir_empty(new_inode);
			if (err)
				goto out;
		}
		new_i_pos = MSDOS_I(new_inode)->i_pos;
		fat_detach(new_inode);
	} else {
		err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
				      &ts, &sinfo);
		if (err)
			goto out;
		new_i_pos = sinfo.i_pos;
	}
	new_dir->i_version++;

	fat_detach(old_inode);
	fat_attach(old_inode, new_i_pos);
	if (is_hid)
		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
	else
		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
	if (IS_DIRSYNC(new_dir)) {
		err = fat_sync_inode(old_inode);
		if (err)
			goto error_inode;
	} else
		mark_inode_dirty(old_inode);

	if (update_dotdot) {
		int start = MSDOS_I(new_dir)->i_logstart;
		dotdot_de->start = cpu_to_le16(start);
		dotdot_de->starthi = cpu_to_le16(start >> 16);
		mark_buffer_dirty_inode(dotdot_bh, old_inode);
		if (IS_DIRSYNC(new_dir)) {
			err = sync_dirty_buffer(dotdot_bh);
			if (err)
				goto error_dotdot;
		}
		drop_nlink(old_dir);
		if (!new_inode)
			inc_nlink(new_dir);
	}

	err = fat_remove_entries(old_dir, &old_sinfo);	
	old_sinfo.bh = NULL;
	if (err)
		goto error_dotdot;
	old_dir->i_version++;
	old_dir->i_ctime = old_dir->i_mtime = ts;
	if (IS_DIRSYNC(old_dir))
		(void)fat_sync_inode(old_dir);
	else
		mark_inode_dirty(old_dir);

	if (new_inode) {
		drop_nlink(new_inode);
		if (is_dir)
			drop_nlink(new_inode);
		new_inode->i_ctime = ts;
	}
out:
	brelse(sinfo.bh);
	brelse(dotdot_bh);
	brelse(old_sinfo.bh);
	return err;

error_dotdot:
	
	corrupt = 1;

	if (update_dotdot) {
		int start = MSDOS_I(old_dir)->i_logstart;
		dotdot_de->start = cpu_to_le16(start);
		dotdot_de->starthi = cpu_to_le16(start >> 16);
		mark_buffer_dirty_inode(dotdot_bh, old_inode);
		corrupt |= sync_dirty_buffer(dotdot_bh);
	}
error_inode:
	fat_detach(old_inode);
	fat_attach(old_inode, old_sinfo.i_pos);
	MSDOS_I(old_inode)->i_attrs = old_attrs;
	if (new_inode) {
		fat_attach(new_inode, new_i_pos);
		if (corrupt)
			corrupt |= fat_sync_inode(new_inode);
	} else {
		int err2 = fat_remove_entries(new_dir, &sinfo);
		if (corrupt)
			corrupt |= err2;
		sinfo.bh = NULL;
	}
	if (corrupt < 0) {
		fat_fs_error(new_dir->i_sb,
			     "%s: Filesystem corrupted (i_pos %lld)",
			     __func__, sinfo.i_pos);
	}
	goto out;
}
Beispiel #18
0
static int do_vxext_rename(struct inode *old_dir, unsigned char *old_name,
			   struct dentry *old_dentry,
			   struct inode *new_dir, unsigned char *new_name,
			   struct dentry *new_dentry, int is_hid)
{
	struct buffer_head *dotdot_bh;
	struct msdos_dir_entry *dotdot_de;
	struct inode *old_inode, *new_inode;
	struct fat_slot_info old_sinfo, sinfo;
	struct timespec ts;
	loff_t new_i_pos;
	int err, old_attrs, is_dir, update_dotdot, corrupt = 0;

	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
	old_inode = old_dentry->d_inode;
	new_inode = new_dentry->d_inode;

	err = fat_scan(old_dir, old_name, &old_sinfo);
	if (err) {
		err = -EIO;
		goto out;
	}

	is_dir = S_ISDIR(old_inode->i_mode);
	update_dotdot = (is_dir && old_dir != new_dir);
	if (update_dotdot) {
		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
			err = -EIO;
			goto out;
		}
	}

	old_attrs = MSDOS_I(old_inode)->i_attrs;
	err = fat_scan(new_dir, new_name, &sinfo);
	if (!err) {
		if (!new_inode) {
			/* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
			if (sinfo.de != old_sinfo.de) {
				err = -EINVAL;
				goto out;
			}
			if (is_hid)
				MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
			else
				MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
			if (IS_DIRSYNC(old_dir)) {
				err = fat_sync_inode(old_inode);
				if (err) {
					MSDOS_I(old_inode)->i_attrs = old_attrs;
					goto out;
				}
			} else
				mark_inode_dirty(old_inode);

			old_dir->i_version++;
			old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
			if (IS_DIRSYNC(old_dir))
				(void)fat_sync_inode(old_dir);
			else
				mark_inode_dirty(old_dir);
			goto out;
		}
	}

	ts = CURRENT_TIME_SEC;
	if (new_inode) {
		if (err)
			goto out;
		if (is_dir) {
			err = fat_dir_empty(new_inode);
			if (err)
				goto out;
		}
		new_i_pos = MSDOS_I(new_inode)->i_pos;
		fat_detach(new_inode);
	} else {
		err = vxext_add_entry(new_dir, new_name, is_dir, is_hid, 0,
				      &ts, &sinfo);
		if (err)
			goto out;
		new_i_pos = sinfo.i_pos;
	}
	new_dir->i_version++;

	fat_detach(old_inode);
	fat_attach(old_inode, new_i_pos);
	if (is_hid)
		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
	else
		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
	if (IS_DIRSYNC(new_dir)) {
		err = fat_sync_inode(old_inode);
		if (err)
			goto error_inode;
	} else
		mark_inode_dirty(old_inode);

	if (update_dotdot) {
		fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
		mark_buffer_dirty_inode(dotdot_bh, old_inode);
		if (IS_DIRSYNC(new_dir)) {
			err = sync_dirty_buffer(dotdot_bh);
			if (err)
				goto error_dotdot;
		}
		drop_nlink(old_dir);
		if (!new_inode)
			inc_nlink(new_dir);
	}

	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
	old_sinfo.bh = NULL;
	if (err)
		goto error_dotdot;
	old_dir->i_version++;
	old_dir->i_ctime = old_dir->i_mtime = ts;
	if (IS_DIRSYNC(old_dir))
		(void)fat_sync_inode(old_dir);
	else
		mark_inode_dirty(old_dir);

	if (new_inode) {
		drop_nlink(new_inode);
		if (is_dir)
			drop_nlink(new_inode);
		new_inode->i_ctime = ts;
	}
out:
	brelse(sinfo.bh);
	brelse(dotdot_bh);
	brelse(old_sinfo.bh);
	return err;

error_dotdot:
	/* data cluster is shared, serious corruption */
	corrupt = 1;

	if (update_dotdot) {
		fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
		mark_buffer_dirty_inode(dotdot_bh, old_inode);
		corrupt |= sync_dirty_buffer(dotdot_bh);
	}
error_inode:
	fat_detach(old_inode);
	fat_attach(old_inode, old_sinfo.i_pos);
	MSDOS_I(old_inode)->i_attrs = old_attrs;
	if (new_inode) {
		fat_attach(new_inode, new_i_pos);
		if (corrupt)
			corrupt |= fat_sync_inode(new_inode);
	} else {
		/*
		 * If new entry was not sharing the data cluster, it
		 * shouldn't be serious corruption.
		 */
		int err2 = fat_remove_entries(new_dir, &sinfo);
		if (corrupt)
			corrupt |= err2;
		sinfo.bh = NULL;
	}
	if (corrupt < 0) {
		fat_fs_error(new_dir->i_sb,
			     "%s: Filesystem corrupted (i_pos %lld)",
			     __func__, sinfo.i_pos);
	}
	goto out;
}
Beispiel #19
0
int
affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
	struct super_block	*sb = dir->i_sb;
	struct buffer_head	*bh;
	struct inode		*inode;
	char			*p;
	int			 i, maxlen, error;
	char			 c, lc;

	pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
		 (int)dentry->d_name.len,dentry->d_name.name,symname);

	maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
	inode  = affs_new_inode(dir);
	if (!inode)
		return -ENOSPC;

	inode->i_op = &affs_symlink_inode_operations;
	inode->i_data.a_ops = &affs_symlink_aops;
	inode->i_mode = S_IFLNK | 0777;
	mode_to_prot(inode);

	error = -EIO;
	bh = affs_bread(sb, inode->i_ino);
	if (!bh)
		goto err;
	i  = 0;
	p  = (char *)AFFS_HEAD(bh)->table;
	lc = '/';
	if (*symname == '/') {
		struct affs_sb_info *sbi = AFFS_SB(sb);
		while (*symname == '/')
			symname++;
		spin_lock(&sbi->symlink_lock);
		while (sbi->s_volume[i])	/* Cannot overflow */
			*p++ = sbi->s_volume[i++];
		spin_unlock(&sbi->symlink_lock);
	}
	while (i < maxlen && (c = *symname++)) {
		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
			*p++ = '/';
			i++;
			symname += 2;
			lc = '/';
		} else if (c == '.' && lc == '/' && *symname == '/') {
			symname++;
			lc = '/';
		} else {
			*p++ = c;
			lc   = c;
			i++;
		}
		if (lc == '/')
			while (*symname == '/')
				symname++;
	}
	*p = 0;
	mark_buffer_dirty_inode(bh, inode);
	affs_brelse(bh);
	mark_inode_dirty(inode);

	error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
	if (error)
		goto err;

	return 0;

err:
	inode->i_nlink = 0;
	mark_inode_dirty(inode);
	iput(inode);
	return error;
}
Beispiel #20
0
static int
affs_remove_link(struct dentry *dentry)
{
    struct inode *dir, *inode = dentry->d_inode;
    struct super_block *sb = inode->i_sb;
    struct buffer_head *bh = NULL, *link_bh = NULL;
    u32 link_ino, ino;
    int retval;

    pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
    retval = -EIO;
    bh = affs_bread(sb, inode->i_ino);
    if (!bh)
        goto done;

    link_ino = (u32)(long)dentry->d_fsdata;
    if (inode->i_ino == link_ino) {
        /* we can't remove the head of the link, as its blocknr is still used as ino,
         * so we remove the block of the first link instead.
         */
        link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;

        dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
        if (IS_ERR(dir)) {
            retval = PTR_ERR(dir);
            goto done;
        }

        affs_lock_dir(dir);
        affs_fix_dcache(dentry, link_ino);
        retval = affs_remove_hash(dir, link_bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(link_bh, inode);

        memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
        retval = affs_insert_hash(dir, bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(bh, inode);

        affs_unlock_dir(dir);
        iput(dir);
    } else {
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;
    }

    while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
        if (ino == link_ino) {
            __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
            AFFS_TAIL(sb, bh)->link_chain = ino2;
            affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
            mark_buffer_dirty_inode(bh, inode);
            retval = 0;
            /* Fix the link count, if bh is a normal header block without links */
            switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
            case ST_LINKDIR:
            case ST_LINKFILE:
                break;
            default:
                if (!AFFS_TAIL(sb, bh)->link_chain)
                    inode->i_nlink = 1;
            }
            affs_free_block(sb, link_ino);
            goto done;
        }
        affs_brelse(bh);
        bh = affs_bread(sb, ino);
        if (!bh)
            goto done;
    }
    retval = -ENOENT;
done:
    affs_brelse(link_bh);
    affs_brelse(bh);
    return retval;
}
Beispiel #21
0
int
affs_remove_header(struct dentry *dentry)
{
    struct super_block *sb;
    struct inode *inode, *dir;
    struct buffer_head *bh = NULL;
    int retval;

    dir = dentry->d_parent->d_inode;
    sb = dir->i_sb;

    retval = -ENOENT;
    inode = dentry->d_inode;
    if (!inode)
        goto done;

    pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
    retval = -EIO;
    bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
    if (!bh)
        goto done;

    affs_lock_link(inode);
    affs_lock_dir(dir);
    switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
    case ST_USERDIR:
        /* if we ever want to support links to dirs
         * i_hash_lock of the inode must only be
         * taken after some checks
         */
        affs_lock_dir(inode);
        retval = affs_empty_dir(inode);
        affs_unlock_dir(inode);
        if (retval)
            goto done_unlock;
        break;
    default:
        break;
    }

    retval = affs_remove_hash(dir, bh);
    if (retval)
        goto done_unlock;
    mark_buffer_dirty_inode(bh, inode);

    affs_unlock_dir(dir);

    if (inode->i_nlink > 1)
        retval = affs_remove_link(dentry);
    else
        inode->i_nlink = 0;
    affs_unlock_link(inode);
    inode->i_ctime = CURRENT_TIME_SEC;
    mark_inode_dirty(inode);

done:
    affs_brelse(bh);
    return retval;

done_unlock:
    affs_unlock_dir(dir);
    affs_unlock_link(inode);
    goto done;
}
Beispiel #22
0
static inline void dirty_indirect(struct buffer_head *bh, struct inode *inode)
{
	mark_buffer_dirty_inode(bh, inode);
	if (IS_SYNC(inode))
		sync_dirty_buffer(bh);
}
Beispiel #23
0
int
affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
{
    struct super_block *sb = dir->i_sb;
    struct buffer_head *inode_bh = NULL;
    struct buffer_head *bh = NULL;
    u32 block = 0;
    int retval;

    pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
             (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);

    retval = -EIO;
    bh = affs_bread(sb, inode->i_ino);
    if (!bh)
        goto done;

    affs_lock_link(inode);
    switch (type) {
    case ST_LINKFILE:
    case ST_LINKDIR:
        retval = -ENOSPC;
        block = affs_alloc_block(dir, dir->i_ino);
        if (!block)
            goto err;
        retval = -EIO;
        inode_bh = bh;
        bh = affs_getzeroblk(sb, block);
        if (!bh)
            goto err;
        break;
    default:
        break;
    }

    AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
    AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
    affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
    AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
    AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);

    if (inode_bh) {
        __be32 chain;
        chain = AFFS_TAIL(sb, inode_bh)->link_chain;
        AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
        AFFS_TAIL(sb, bh)->link_chain = chain;
        AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
        affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
        mark_buffer_dirty_inode(inode_bh, inode);
        inode->i_nlink = 2;
        atomic_inc(&inode->i_count);
    }
    affs_fix_checksum(sb, bh);
    mark_buffer_dirty_inode(bh, inode);
    dentry->d_fsdata = (void *)(long)bh->b_blocknr;

    affs_lock_dir(dir);
    retval = affs_insert_hash(dir, bh);
    mark_buffer_dirty_inode(bh, inode);
    affs_unlock_dir(dir);
    affs_unlock_link(inode);

    d_instantiate(dentry, inode);
done:
    affs_brelse(inode_bh);
    affs_brelse(bh);
    return retval;
err:
    if (block)
        affs_free_block(sb, block);
    affs_unlock_link(inode);
    goto done;
}