示例#1
0
/*
 * utility function that does setup for reiserfs_new_inode.
 * dquot_initialize needs lots of credits so it's better to have it
 * outside of a transaction, so we had to pull some bits of
 * reiserfs_new_inode out into this func.
 */
static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode)
{
	/*
	 * Make inode invalid - just in case we are going to drop it before
	 * the initialization happens
	 */
	INODE_PKEY(inode)->k_objectid = 0;

	/*
	 * the quota init calls have to know who to charge the quota to, so
	 * we have to set uid and gid here
	 */
	inode_init_owner(inode, dir, mode);
	return dquot_initialize(inode);
}
static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
	struct inode * inode;
	int err = -EMLINK;

	if (dir->i_nlink >= UFS_LINK_MAX)
		goto out;

	dquot_initialize(dir);

	lock_kernel();
	inode_inc_link_count(dir);

	inode = ufs_new_inode(dir, S_IFDIR|mode);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out_dir;

	inode->i_op = &ufs_dir_inode_operations;
	inode->i_fop = &ufs_dir_operations;
	inode->i_mapping->a_ops = &ufs_aops;

	inode_inc_link_count(inode);

	err = ufs_make_empty(inode, dir);
	if (err)
		goto out_fail;

	err = ufs_add_link(dentry, inode);
	if (err)
		goto out_fail;
	unlock_kernel();

	d_instantiate(dentry, inode);
out:
	return err;

out_fail:
	inode_dec_link_count(inode);
	inode_dec_link_count(inode);
	iput (inode);
out_dir:
	inode_dec_link_count(dir);
	unlock_kernel();
	goto out;
}
示例#3
0
static int ext2_symlink (struct inode * dir, struct dentry * dentry,
                         const char * symname)
{
    struct super_block * sb = dir->i_sb;
    int err = -ENAMETOOLONG;
    unsigned l = strlen(symname)+1;
    struct inode * inode;

    if (l > sb->s_blocksize)
        goto out;

    dquot_initialize(dir);

    inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name);
    err = PTR_ERR(inode);
    if (IS_ERR(inode))
        goto out;

    if (l > sizeof (EXT2_I(inode)->i_data)) {
        /* slow symlink */
        inode->i_op = &ext2_symlink_inode_operations;
        if (test_opt(inode->i_sb, NOBH))
            inode->i_mapping->a_ops = &ext2_nobh_aops;
        else
            inode->i_mapping->a_ops = &ext2_aops;
        err = page_symlink(inode, symname, l);
        if (err)
            goto out_fail;
    } else {
        /* fast symlink */
        inode->i_op = &ext2_fast_symlink_inode_operations;
        memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
        inode->i_size = l-1;
    }
    mark_inode_dirty(inode);

    err = ext2_add_nondir(dentry, inode);
out:
    return err;

out_fail:
    inode_dec_link_count(inode);
    unlock_new_inode(inode);
    iput (inode);
    goto out;
}
示例#4
0
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
{
    struct inode * inode;
    int err;

    dquot_initialize(dir);

    inode_inc_link_count(dir);

    inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
    err = PTR_ERR(inode);
    if (IS_ERR(inode))
        goto out_dir;

    inode->i_op = &ext2_dir_inode_operations;
    inode->i_fop = &ext2_dir_operations;
    if (test_opt(inode->i_sb, NOBH))
        inode->i_mapping->a_ops = &ext2_nobh_aops;
    else
        inode->i_mapping->a_ops = &ext2_aops;

    inode_inc_link_count(inode);

    err = ext2_make_empty(inode, dir);
    if (err)
        goto out_fail;

    err = ext2_add_link(dentry, inode);
    if (err)
        goto out_fail;

    unlock_new_inode(inode);
    d_instantiate(dentry, inode);
out:
    return err;

out_fail:
    inode_dec_link_count(inode);
    inode_dec_link_count(inode);
    unlock_new_inode(inode);
    iput(inode);
out_dir:
    inode_dec_link_count(dir);
    goto out;
}
static int ufs_symlink (struct inode * dir, struct dentry * dentry,
	const char * symname)
{
	struct super_block * sb = dir->i_sb;
	int err = -ENAMETOOLONG;
	unsigned l = strlen(symname)+1;
	struct inode * inode;

	if (l > sb->s_blocksize)
		goto out_notlocked;

	dquot_initialize(dir);

	lock_kernel();
	inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out;

	if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
		/* slow symlink */
		inode->i_op = &ufs_symlink_inode_operations;
		inode->i_mapping->a_ops = &ufs_aops;
		err = page_symlink(inode, symname, l);
		if (err)
			goto out_fail;
	} else {
		/* fast symlink */
		inode->i_op = &ufs_fast_symlink_inode_operations;
		memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l);
		inode->i_size = l-1;
	}
	mark_inode_dirty(inode);

	err = ufs_add_nondir(dentry, inode);
out:
	unlock_kernel();
out_notlocked:
	return err;

out_fail:
	inode_dec_link_count(inode);
	iput(inode);
	goto out;
}
示例#6
0
文件: namei.c 项目: mdamt/linux
static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
						bool excl)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	nid_t ino = 0;
	int err;

	err = dquot_initialize(dir);
	if (err)
		return err;

	inode = f2fs_new_inode(dir, mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
		set_cold_files(sbi, inode, dentry->d_name.name);

	inode->i_op = &f2fs_file_inode_operations;
	inode->i_fop = &f2fs_file_operations;
	inode->i_mapping->a_ops = &f2fs_dblock_aops;
	ino = inode->i_ino;

	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out;
	f2fs_unlock_op(sbi);

	alloc_nid_done(sbi, ino);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);

	f2fs_balance_fs(sbi, true);
	return 0;
out:
	handle_failed_inode(inode);
	return err;
}
示例#7
0
文件: namei.c 项目: mdamt/linux
static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	int err;

	err = dquot_initialize(dir);
	if (err)
		return err;

	inode = f2fs_new_inode(dir, S_IFDIR | mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	inode->i_op = &f2fs_dir_inode_operations;
	inode->i_fop = &f2fs_dir_operations;
	inode->i_mapping->a_ops = &f2fs_dblock_aops;
	mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);

	set_inode_flag(inode, FI_INC_LINK);
	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out_fail;
	f2fs_unlock_op(sbi);

	alloc_nid_done(sbi, inode->i_ino);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);

	f2fs_balance_fs(sbi, true);
	return 0;

out_fail:
	clear_inode_flag(inode, FI_INC_LINK);
	handle_failed_inode(inode);
	return err;
}
示例#8
0
文件: inode.c 项目: aejsmith/linux
/*
 * Called at the last iput() if i_nlink is zero.
 */
void ext2_evict_inode(struct inode * inode)
{
	struct ext2_block_alloc_info *rsv;
	int want_delete = 0;

	if (!inode->i_nlink && !is_bad_inode(inode)) {
		want_delete = 1;
		dquot_initialize(inode);
	} else {
		dquot_drop(inode);
	}

	truncate_inode_pages_final(&inode->i_data);

	if (want_delete) {
		sb_start_intwrite(inode->i_sb);
		/* set dtime */
		EXT2_I(inode)->i_dtime	= get_seconds();
		mark_inode_dirty(inode);
		__ext2_write_inode(inode, inode_needs_sync(inode));
		/* truncate to 0 */
		inode->i_size = 0;
		if (inode->i_blocks)
			ext2_truncate_blocks(inode, 0);
		ext2_xattr_delete_inode(inode);
	}

	invalidate_inode_buffers(inode);
	clear_inode(inode);

	ext2_discard_reservation(inode);
	rsv = EXT2_I(inode)->i_block_alloc_info;
	EXT2_I(inode)->i_block_alloc_info = NULL;
	if (unlikely(rsv))
		kfree(rsv);

	if (want_delete) {
		ext2_free_inode(inode);
		sb_end_intwrite(inode->i_sb);
	}
}
示例#9
0
static int ext2_link (struct dentry * old_dentry, struct inode * dir,
                      struct dentry *dentry)
{
    struct inode *inode = old_dentry->d_inode;
    int err;

    dquot_initialize(dir);

    inode->i_ctime = CURRENT_TIME_SEC;
    inode_inc_link_count(inode);
    ihold(inode);

    err = ext2_add_link(dentry, inode);
    if (!err) {
        d_instantiate(dentry, inode);
        return 0;
    }
    inode_dec_link_count(inode);
    iput(inode);
    return err;
}
示例#10
0
/*
 * By the time this is called, we already have created
 * the directory cache entry for the new file, but it
 * is so far negative - it has no inode.
 *
 * If the create succeeds, we fill in the inode information
 * with d_instantiate().
 */
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
{
    struct inode *inode;

    dquot_initialize(dir);

    inode = ext2_new_inode(dir, mode, &dentry->d_name);
    if (IS_ERR(inode))
        return PTR_ERR(inode);

    inode->i_op = &ext2_file_inode_operations;
    if (test_opt(inode->i_sb, NOBH)) {
        inode->i_mapping->a_ops = &ext2_nobh_aops;
        inode->i_fop = &ext2_file_operations;
    } else {
        inode->i_mapping->a_ops = &ext2_aops;
        inode->i_fop = &ext2_file_operations;
    }
    mark_inode_dirty(inode);
    return ext2_add_nondir(dentry, inode);
}
示例#11
0
文件: file.c 项目: AshishNamdev/linux
int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
	struct inode *inode = d_inode(dentry);
	int rc;

	rc = setattr_prepare(dentry, iattr);
	if (rc)
		return rc;

	if (is_quota_modification(inode, iattr)) {
		rc = dquot_initialize(inode);
		if (rc)
			return rc;
	}
	if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
	    (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
		rc = dquot_transfer(inode, iattr);
		if (rc)
			return rc;
	}

	if ((iattr->ia_valid & ATTR_SIZE) &&
	    iattr->ia_size != i_size_read(inode)) {
		inode_dio_wait(inode);

		rc = inode_newsize_ok(inode, iattr->ia_size);
		if (rc)
			return rc;

		truncate_setsize(inode, iattr->ia_size);
		jfs_truncate(inode);
	}

	setattr_copy(inode, iattr);
	mark_inode_dirty(inode);

	if (iattr->ia_valid & ATTR_MODE)
		rc = posix_acl_chmod(inode, inode->i_mode);
	return rc;
}
示例#12
0
文件: namei.c 项目: mdamt/linux
static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode = d_inode(dentry);
	struct f2fs_dir_entry *de;
	struct page *page;
	int err = -ENOENT;

	trace_f2fs_unlink_enter(dir, dentry);

	err = dquot_initialize(dir);
	if (err)
		return err;

	de = f2fs_find_entry(dir, &dentry->d_name, &page);
	if (!de) {
		if (IS_ERR(page))
			err = PTR_ERR(page);
		goto fail;
	}

	f2fs_balance_fs(sbi, true);

	f2fs_lock_op(sbi);
	err = acquire_orphan_inode(sbi);
	if (err) {
		f2fs_unlock_op(sbi);
		f2fs_dentry_kunmap(dir, page);
		f2fs_put_page(page, 0);
		goto fail;
	}
	f2fs_delete_entry(de, page, dir, inode);
	f2fs_unlock_op(sbi);

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);
fail:
	trace_f2fs_unlink_exit(inode, err);
	return err;
}
示例#13
0
/* utility function that does setup for reiserfs_new_inode.
** dquot_initialize needs lots of credits so it's better to have it
** outside of a transaction, so we had to pull some bits of
** reiserfs_new_inode out into this func.
*/
static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
{

	/* the quota init calls have to know who to charge the quota to, so
	 ** we have to set uid and gid here
	 */
	inode->i_uid = current_fsuid();
	inode->i_mode = mode;
	/* Make inode invalid - just in case we are going to drop it before
	 * the initialization happens */
	INODE_PKEY(inode)->k_objectid = 0;

	if (dir->i_mode & S_ISGID) {
		inode->i_gid = dir->i_gid;
		if (S_ISDIR(mode))
			inode->i_mode |= S_ISGID;
	} else {
		inode->i_gid = current_fsgid();
	}
	dquot_initialize(inode);
	return 0;
}
static int ufs_link (struct dentry * old_dentry, struct inode * dir,
	struct dentry *dentry)
{
	struct inode *inode = old_dentry->d_inode;
	int error;

	lock_kernel();
	if (inode->i_nlink >= UFS_LINK_MAX) {
		unlock_kernel();
		return -EMLINK;
	}

	dquot_initialize(dir);

	inode->i_ctime = CURRENT_TIME_SEC;
	inode_inc_link_count(inode);
	atomic_inc(&inode->i_count);

	error = ufs_add_nondir(dentry, inode);
	unlock_kernel();
	return error;
}
static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
{
	struct inode *inode;
	int err;

	if (!old_valid_dev(rdev))
		return -EINVAL;

	dquot_initialize(dir);

	inode = ufs_new_inode(dir, mode);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		init_special_inode(inode, mode, rdev);
		ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
		mark_inode_dirty(inode);
		lock_kernel();
		err = ufs_add_nondir(dentry, inode);
		unlock_kernel();
	}
	return err;
}
示例#16
0
static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
{
    struct inode * inode;
    int err;

    if (!new_valid_dev(rdev))
        return -EINVAL;

    dquot_initialize(dir);

    inode = ext2_new_inode (dir, mode, &dentry->d_name);
    err = PTR_ERR(inode);
    if (!IS_ERR(inode)) {
        init_special_inode(inode, inode->i_mode, rdev);
#ifdef CONFIG_EXT2_FS_XATTR
        inode->i_op = &ext2_special_inode_operations;
#endif
        mark_inode_dirty(inode);
        err = ext2_add_nondir(dentry, inode);
    }
    return err;
}
示例#17
0
文件: namei.c 项目: mdamt/linux
static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
				umode_t mode, dev_t rdev)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	int err = 0;

	err = dquot_initialize(dir);
	if (err)
		return err;

	inode = f2fs_new_inode(dir, mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	init_special_inode(inode, inode->i_mode, rdev);
	inode->i_op = &f2fs_special_inode_operations;

	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out;
	f2fs_unlock_op(sbi);

	alloc_nid_done(sbi, inode->i_ino);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);

	f2fs_balance_fs(sbi, true);
	return 0;
out:
	handle_failed_inode(inode);
	return err;
}
示例#18
0
文件: namei.c 项目: mdamt/linux
static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
		struct dentry *dentry)
{
	struct inode *inode = d_inode(old_dentry);
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	int err;

	if (f2fs_encrypted_inode(dir) &&
			!fscrypt_has_permitted_context(dir, inode))
		return -EPERM;

	err = dquot_initialize(dir);
	if (err)
		return err;

	f2fs_balance_fs(sbi, true);

	inode->i_ctime = current_time(inode);
	ihold(inode);

	set_inode_flag(inode, FI_INC_LINK);
	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out;
	f2fs_unlock_op(sbi);

	d_instantiate(dentry, inode);

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);
	return 0;
out:
	clear_inode_flag(inode, FI_INC_LINK);
	iput(inode);
	f2fs_unlock_op(sbi);
	return err;
}
示例#19
0
static int ext2_unlink(struct inode * dir, struct dentry *dentry)
{
    struct inode * inode = dentry->d_inode;
    struct ext2_dir_entry_2 * de;
    struct page * page;
    int err = -ENOENT;

    dquot_initialize(dir);

    de = ext2_find_entry (dir, &dentry->d_name, &page);
    if (!de)
        goto out;

    err = ext2_delete_entry (de, page);
    if (err)
        goto out;

    inode->i_ctime = dir->i_ctime;
    inode_dec_link_count(inode);
    err = 0;
out:
    return err;
}
示例#20
0
/*
 * NAME:	jfs_rmdir(dip, dentry)
 *
 * FUNCTION:	remove a link to child directory
 *
 * PARAMETER:	dip	- parent inode
 *		dentry	- child directory dentry
 *
 * RETURN:	-EINVAL	- if name is . or ..
 *		-EINVAL - if . or .. exist but are invalid.
 *		errors from subroutines
 *
 * note:
 * if other threads have the directory open when the last link
 * is removed, the "." and ".." entries, if present, are removed before
 * rmdir() returns and no new entries may be created in the directory,
 * but the directory is not removed until the last reference to
 * the directory is released (cf.unlink() of regular file).
 */
static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
{
    int rc;
    tid_t tid;		/* transaction id */
    struct inode *ip = dentry->d_inode;
    ino_t ino;
    struct component_name dname;
    struct inode *iplist[2];
    struct tblock *tblk;

    jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);

    /* Init inode for quota operations. */
    dquot_initialize(dip);
    dquot_initialize(ip);

    /* directory must be empty to be removed */
    if (!dtEmpty(ip)) {
        rc = -ENOTEMPTY;
        goto out;
    }

    if ((rc = get_UCSname(&dname, dentry))) {
        goto out;
    }

    tid = txBegin(dip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    iplist[0] = dip;
    iplist[1] = ip;

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_DELETE;
    tblk->u.ip = ip;

    /*
     * delete the entry of target directory from parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
        jfs_err("jfs_rmdir: dtDelete returned %d", rc);
        if (rc == -EIO)
            txAbort(tid, 1);
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
        mutex_unlock(&JFS_IP(dip)->commit_mutex);

        goto out2;
    }

    /* update parent directory's link count corresponding
     * to ".." entry of the target directory deleted
     */
    dip->i_ctime = dip->i_mtime = CURRENT_TIME;
    inode_dec_link_count(dip);

    /*
     * OS/2 could have created EA and/or ACL
     */
    /* free EA from both persistent and working map */
    if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
        /* free EA pages */
        txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
    }
    JFS_IP(ip)->ea.flag = 0;

    /* free ACL from both persistent and working map */
    if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
        /* free ACL pages */
        txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
    }
    JFS_IP(ip)->acl.flag = 0;

    /* mark the target directory as deleted */
    clear_nlink(ip);
    mark_inode_dirty(ip);

    rc = txCommit(tid, 2, &iplist[0], 0);

    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);

    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, dip)) {
        if (dip->i_size > 1)
            jfs_truncate_nolock(dip, 0);

        clear_cflag(COMMIT_Stale, dip);
    }

out2:
    free_UCSname(&dname);

out:
    jfs_info("jfs_rmdir: rc:%d", rc);
    return rc;
}
示例#21
0
static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
{
	int retval, err;
	struct inode *inode;
	struct reiserfs_dir_entry de;
	INITIALIZE_PATH(path);
	struct reiserfs_transaction_handle th;
	int jbegin_count;
	unsigned long savelink;
	int depth;

	dquot_initialize(dir);

	inode = dentry->d_inode;

	/* in this transaction we can be doing at max two balancings and update
	 * two stat datas, we change quotas of the owner of the directory and of
	 * the owner of the parent directory. The quota structure is possibly
	 * deleted only on iput => outside of this transaction */
	jbegin_count =
	    JOURNAL_PER_BALANCE_CNT * 2 + 2 +
	    4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);

	depth = reiserfs_write_lock_once(dir->i_sb);
	retval = journal_begin(&th, dir->i_sb, jbegin_count);
	if (retval)
		goto out_unlink;

	de.de_gen_number_bit_string = NULL;
	if ((retval =
	     reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
				 &path, &de)) == NAME_NOT_FOUND) {
		retval = -ENOENT;
		goto end_unlink;
	} else if (retval == IO_ERROR) {
		retval = -EIO;
		goto end_unlink;
	}

	reiserfs_update_inode_transaction(inode);
	reiserfs_update_inode_transaction(dir);

	if (de.de_objectid != inode->i_ino) {
		// FIXME: compare key of an object and a key found in the
		// entry
		retval = -EIO;
		goto end_unlink;
	}

	if (!inode->i_nlink) {
		reiserfs_warning(inode->i_sb, "reiserfs-7042",
				 "deleting nonexistent file (%lu), %d",
				 inode->i_ino, inode->i_nlink);
		set_nlink(inode, 1);
	}

	drop_nlink(inode);

	/*
	 * we schedule before doing the add_save_link call, save the link
	 * count so we don't race
	 */
	savelink = inode->i_nlink;

	retval =
	    reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL,
				   0);
	if (retval < 0) {
		inc_nlink(inode);
		goto end_unlink;
	}
	inode->i_ctime = CURRENT_TIME_SEC;
	reiserfs_update_sd(&th, inode);

	dir->i_size -= (de.de_entrylen + DEH_SIZE);
	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
	reiserfs_update_sd(&th, dir);

	if (!savelink)
		/* prevent file from getting lost */
		add_save_link(&th, inode, 0 /* not truncate */ );

	retval = journal_end(&th, dir->i_sb, jbegin_count);
	reiserfs_check_path(&path);
	reiserfs_write_unlock_once(dir->i_sb, depth);
	return retval;

      end_unlink:
	pathrelse(&path);
	err = journal_end(&th, dir->i_sb, jbegin_count);
	reiserfs_check_path(&path);
	if (err)
		retval = err;
      out_unlink:
	reiserfs_write_unlock_once(dir->i_sb, depth);
	return retval;
}
示例#22
0
static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                       const char *name)
{
    int rc;
    tid_t tid;
    ino_t ino = 0;
    struct component_name dname;
    int ssize;		/* source pathname size */
    struct btstack btstack;
    struct inode *ip = dentry->d_inode;
    unchar *i_fastsymlink;
    s64 xlen = 0;
    int bmask = 0, xsize;
    s64 extent = 0, xaddr;
    struct metapage *mp;
    struct super_block *sb;
    struct tblock *tblk;

    struct inode *iplist[2];

    jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);

    dquot_initialize(dip);

    ssize = strlen(name) + 1;

    /*
     * search parent directory for entry/freespace
     * (dtSearch() returns parent directory page pinned)
     */

    if ((rc = get_UCSname(&dname, dentry)))
        goto out1;

    /*
     * allocate on-disk/in-memory inode for symbolic link:
     * (iAlloc() returns new, locked inode)
     */
    ip = ialloc(dip, S_IFLNK | 0777);
    if (IS_ERR(ip)) {
        rc = PTR_ERR(ip);
        goto out2;
    }

    tid = txBegin(dip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
    if (rc)
        goto out3;

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_CREATE;
    tblk->ino = ip->i_ino;
    tblk->u.ixpxd = JFS_IP(ip)->ixpxd;

    /* fix symlink access permission
     * (dir_create() ANDs in the u.u_cmask,
     * but symlinks really need to be 777 access)
     */
    ip->i_mode |= 0777;

    /*
     * write symbolic link target path name
     */
    xtInitRoot(tid, ip);

    /*
     * write source path name inline in on-disk inode (fast symbolic link)
     */

    if (ssize <= IDATASIZE) {
        ip->i_op = &jfs_fast_symlink_inode_operations;

        i_fastsymlink = JFS_IP(ip)->i_inline;
        memcpy(i_fastsymlink, name, ssize);
        ip->i_size = ssize - 1;

        /*
         * if symlink is > 128 bytes, we don't have the space to
         * store inline extended attributes
         */
        if (ssize > sizeof (JFS_IP(ip)->i_inline))
            JFS_IP(ip)->mode2 &= ~INLINEEA;

        jfs_info("jfs_symlink: fast symlink added  ssize:%d name:%s ",
                 ssize, name);
    }
    /*
     * write source path name in a single extent
     */
    else {
        jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);

        ip->i_op = &jfs_symlink_inode_operations;
        ip->i_mapping->a_ops = &jfs_aops;

        /*
         * even though the data of symlink object (source
         * path name) is treated as non-journaled user data,
         * it is read/written thru buffer cache for performance.
         */
        sb = ip->i_sb;
        bmask = JFS_SBI(sb)->bsize - 1;
        xsize = (ssize + bmask) & ~bmask;
        xaddr = 0;
        xlen = xsize >> JFS_SBI(sb)->l2bsize;
        if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
            txAbort(tid, 0);
            goto out3;
        }
        extent = xaddr;
        ip->i_size = ssize - 1;
        while (ssize) {
            /* This is kind of silly since PATH_MAX == 4K */
            int copy_size = min(ssize, PSIZE);

            mp = get_metapage(ip, xaddr, PSIZE, 1);

            if (mp == NULL) {
                xtTruncate(tid, ip, 0, COMMIT_PWMAP);
                rc = -EIO;
                txAbort(tid, 0);
                goto out3;
            }
            memcpy(mp->data, name, copy_size);
            flush_metapage(mp);
            ssize -= copy_size;
            name += copy_size;
            xaddr += JFS_SBI(sb)->nbperpage;
        }
    }

    /*
     * create entry for symbolic link in parent directory
     */
    rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
    if (rc == 0) {
        ino = ip->i_ino;
        rc = dtInsert(tid, dip, &dname, &ino, &btstack);
    }
    if (rc) {
        if (xlen)
            xtTruncate(tid, ip, 0, COMMIT_PWMAP);
        txAbort(tid, 0);
        /* discard new inode */
        goto out3;
    }

    mark_inode_dirty(ip);

    dip->i_ctime = dip->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dip);
    /*
     * commit update of parent directory and link object
     */

    iplist[0] = dip;
    iplist[1] = ip;
    rc = txCommit(tid, 2, &iplist[0], 0);

out3:
    txEnd(tid);
    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);
    if (rc) {
        free_ea_wmap(ip);
        ip->i_nlink = 0;
        unlock_new_inode(ip);
        iput(ip);
    } else {
        d_instantiate(dentry, ip);
        unlock_new_inode(ip);
    }

out2:
    free_UCSname(&dname);

out1:
    jfs_info("jfs_symlink: rc:%d", rc);
    return rc;
}
示例#23
0
/*
 * NAME:	jfs_link(vp, dvp, name, crp)
 *
 * FUNCTION:	create a link to <vp> by the name = <name>
 *		in the parent directory <dvp>
 *
 * PARAMETER:	vp	- target object
 *		dvp	- parent directory of new link
 *		name	- name of new link to target object
 *		crp	- credential
 *
 * RETURN:	Errors from subroutines
 *
 * note:
 * JFS does NOT support link() on directories (to prevent circular
 * path in the directory hierarchy);
 * EPERM: the target object is a directory, and either the caller
 * does not have appropriate privileges or the implementation prohibits
 * using link() on directories [XPG4.2].
 *
 * JFS does NOT support links between file systems:
 * EXDEV: target object and new link are on different file systems and
 * implementation does not support links between file systems [XPG4.2].
 */
static int jfs_link(struct dentry *old_dentry,
                    struct inode *dir, struct dentry *dentry)
{
    int rc;
    tid_t tid;
    struct inode *ip = old_dentry->d_inode;
    ino_t ino;
    struct component_name dname;
    struct btstack btstack;
    struct inode *iplist[2];

    jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
             dentry->d_name.name);

    if (ip->i_nlink == JFS_LINK_MAX)
        return -EMLINK;

    dquot_initialize(dir);

    tid = txBegin(ip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    /*
     * scan parent directory for entry/freespace
     */
    if ((rc = get_UCSname(&dname, dentry)))
        goto out;

    if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
        goto free_dname;

    /*
     * create entry for new link in parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
        goto free_dname;

    /* update object inode */
    inc_nlink(ip);		/* for new link */
    ip->i_ctime = CURRENT_TIME;
    dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dir);
    ihold(ip);

    iplist[0] = ip;
    iplist[1] = dir;
    rc = txCommit(tid, 2, &iplist[0], 0);

    if (rc) {
        ip->i_nlink--; /* never instantiated */
        iput(ip);
    } else
        d_instantiate(dentry, ip);

free_dname:
    free_UCSname(&dname);

out:
    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dir)->commit_mutex);

    jfs_info("jfs_link: rc:%d", rc);
    return rc;
}
示例#24
0
static void ocfs2_delete_inode(struct inode *inode)
{
	int wipe, status;
	sigset_t oldset;
	struct buffer_head *di_bh = NULL;

	trace_ocfs2_delete_inode(inode->i_ino,
				 (unsigned long long)OCFS2_I(inode)->ip_blkno,
				 is_bad_inode(inode));

	/* When we fail in read_inode() we mark inode as bad. The second test
	 * catches the case when inode allocation fails before allocating
	 * a block for inode. */
	if (is_bad_inode(inode) || !OCFS2_I(inode)->ip_blkno)
		goto bail;

	dquot_initialize(inode);

	if (!ocfs2_inode_is_valid_to_delete(inode)) {
		/* It's probably not necessary to truncate_inode_pages
		 * here but we do it for safety anyway (it will most
		 * likely be a no-op anyway) */
		ocfs2_cleanup_delete_inode(inode, 0);
		goto bail;
	}

	/* We want to block signals in delete_inode as the lock and
	 * messaging paths may return us -ERESTARTSYS. Which would
	 * cause us to exit early, resulting in inodes being orphaned
	 * forever. */
	ocfs2_block_signals(&oldset);

	/*
	 * Synchronize us against ocfs2_get_dentry. We take this in
	 * shared mode so that all nodes can still concurrently
	 * process deletes.
	 */
	status = ocfs2_nfs_sync_lock(OCFS2_SB(inode->i_sb), 0);
	if (status < 0) {
		mlog(ML_ERROR, "getting nfs sync lock(PR) failed %d\n", status);
		ocfs2_cleanup_delete_inode(inode, 0);
		goto bail_unblock;
	}
	/* Lock down the inode. This gives us an up to date view of
	 * it's metadata (for verification), and allows us to
	 * serialize delete_inode on multiple nodes.
	 *
	 * Even though we might be doing a truncate, we don't take the
	 * allocation lock here as it won't be needed - nobody will
	 * have the file open.
	 */
	status = ocfs2_inode_lock(inode, &di_bh, 1);
	if (status < 0) {
		if (status != -ENOENT)
			mlog_errno(status);
		ocfs2_cleanup_delete_inode(inode, 0);
		goto bail_unlock_nfs_sync;
	}

	/* Query the cluster. This will be the final decision made
	 * before we go ahead and wipe the inode. */
	status = ocfs2_query_inode_wipe(inode, di_bh, &wipe);
	if (!wipe || status < 0) {
		/* Error and remote inode busy both mean we won't be
		 * removing the inode, so they take almost the same
		 * path. */
		if (status < 0)
			mlog_errno(status);

		/* Someone in the cluster has disallowed a wipe of
		 * this inode, or it was never completely
		 * orphaned. Write out the pages and exit now. */
		ocfs2_cleanup_delete_inode(inode, 1);
		goto bail_unlock_inode;
	}

	ocfs2_cleanup_delete_inode(inode, 0);

	status = ocfs2_wipe_inode(inode, di_bh);
	if (status < 0) {
		if (status != -EDEADLK)
			mlog_errno(status);
		goto bail_unlock_inode;
	}

	/*
	 * Mark the inode as successfully deleted.
	 *
	 * This is important for ocfs2_clear_inode() as it will check
	 * this flag and skip any checkpointing work
	 *
	 * ocfs2_stuff_meta_lvb() also uses this flag to invalidate
	 * the LVB for other nodes.
	 */
	OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED;

bail_unlock_inode:
	ocfs2_inode_unlock(inode, 1);
	brelse(di_bh);

bail_unlock_nfs_sync:
	ocfs2_nfs_sync_unlock(OCFS2_SB(inode->i_sb), 0);

bail_unblock:
	ocfs2_unblock_signals(&oldset);
bail:
	return;
}
示例#25
0
/*
 * NAME:	jfs_mknod
 *
 * FUNCTION:	Create a special file (device)
 */
static int jfs_mknod(struct inode *dir, struct dentry *dentry,
                     int mode, dev_t rdev)
{
    struct jfs_inode_info *jfs_ip;
    struct btstack btstack;
    struct component_name dname;
    ino_t ino;
    struct inode *ip;
    struct inode *iplist[2];
    int rc;
    tid_t tid;
    struct tblock *tblk;

    if (!new_valid_dev(rdev))
        return -EINVAL;

    jfs_info("jfs_mknod: %s", dentry->d_name.name);

    dquot_initialize(dir);

    if ((rc = get_UCSname(&dname, dentry)))
        goto out;

    ip = ialloc(dir, mode);
    if (IS_ERR(ip)) {
        rc = PTR_ERR(ip);
        goto out1;
    }
    jfs_ip = JFS_IP(ip);

    tid = txBegin(dir->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    rc = jfs_init_acl(tid, ip, dir);
    if (rc)
        goto out3;

    rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
    if (rc) {
        txAbort(tid, 0);
        goto out3;
    }

    if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
        txAbort(tid, 0);
        goto out3;
    }

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_CREATE;
    tblk->ino = ip->i_ino;
    tblk->u.ixpxd = JFS_IP(ip)->ixpxd;

    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
        txAbort(tid, 0);
        goto out3;
    }

    ip->i_op = &jfs_file_inode_operations;
    jfs_ip->dev = new_encode_dev(rdev);
    init_special_inode(ip, ip->i_mode, rdev);

    mark_inode_dirty(ip);

    dir->i_ctime = dir->i_mtime = CURRENT_TIME;

    mark_inode_dirty(dir);

    iplist[0] = dir;
    iplist[1] = ip;
    rc = txCommit(tid, 2, iplist, 0);

out3:
    txEnd(tid);
    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dir)->commit_mutex);
    if (rc) {
        free_ea_wmap(ip);
        ip->i_nlink = 0;
        unlock_new_inode(ip);
        iput(ip);
    } else {
        d_instantiate(dentry, ip);
        unlock_new_inode(ip);
    }

out1:
    free_UCSname(&dname);

out:
    jfs_info("jfs_mknod: returning %d", rc);
    return rc;
}
示例#26
0
/*
 * There are two policies for allocating an inode.  If the new inode is
 * a directory, then a forward search is made for a block group with both
 * free space and a low directory-to-inode ratio; if that fails, then of
 * the groups with above-average free space, that group with the fewest
 * directories already is chosen.
 *
 * For other inodes, search forward from the parent directory's block
 * group to find a free inode.
 */
struct inode *ext3_new_inode(handle_t *handle, struct inode * dir,
			     const struct qstr *qstr, int mode)
{
	struct super_block *sb;
	struct buffer_head *bitmap_bh = NULL;
	struct buffer_head *bh2;
	int group;
	unsigned long ino = 0;
	struct inode * inode;
	struct ext3_group_desc * gdp = NULL;
	struct ext3_super_block * es;
	struct ext3_inode_info *ei;
	struct ext3_sb_info *sbi;
	int err = 0;
	struct inode *ret;
	int i;

	/* Cannot create files in a deleted directory */
	if (!dir || !dir->i_nlink)
		return ERR_PTR(-EPERM);

	sb = dir->i_sb;
	trace_ext3_request_inode(dir, mode);
	inode = new_inode(sb);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	ei = EXT3_I(inode);

	sbi = EXT3_SB(sb);
	es = sbi->s_es;
	if (S_ISDIR(mode)) {
		if (test_opt (sb, OLDALLOC))
			group = find_group_dir(sb, dir);
		else
			group = find_group_orlov(sb, dir);
	} else
		group = find_group_other(sb, dir);

	err = -ENOSPC;
	if (group == -1)
		goto out;

	for (i = 0; i < sbi->s_groups_count; i++) {
		err = -EIO;

		gdp = ext3_get_group_desc(sb, group, &bh2);
		if (!gdp)
			goto fail;

		brelse(bitmap_bh);
		bitmap_bh = read_inode_bitmap(sb, group);
		if (!bitmap_bh)
			goto fail;

		ino = 0;

repeat_in_this_group:
		ino = ext3_find_next_zero_bit((unsigned long *)
				bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino);
		if (ino < EXT3_INODES_PER_GROUP(sb)) {

			BUFFER_TRACE(bitmap_bh, "get_write_access");
			err = ext3_journal_get_write_access(handle, bitmap_bh);
			if (err)
				goto fail;

			if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
						ino, bitmap_bh->b_data)) {
				/* we won it */
				BUFFER_TRACE(bitmap_bh,
					"call ext3_journal_dirty_metadata");
				err = ext3_journal_dirty_metadata(handle,
								bitmap_bh);
				if (err)
					goto fail;
				goto got;
			}
			/* we lost it */
			journal_release_buffer(handle, bitmap_bh);

			if (++ino < EXT3_INODES_PER_GROUP(sb))
				goto repeat_in_this_group;
		}

		/*
		 * This case is possible in concurrent environment.  It is very
		 * rare.  We cannot repeat the find_group_xxx() call because
		 * that will simply return the same blockgroup, because the
		 * group descriptor metadata has not yet been updated.
		 * So we just go onto the next blockgroup.
		 */
		if (++group == sbi->s_groups_count)
			group = 0;
	}
	err = -ENOSPC;
	goto out;

got:
	ino += group * EXT3_INODES_PER_GROUP(sb) + 1;
	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
		ext3_error (sb, "ext3_new_inode",
			    "reserved inode or inode > inodes count - "
			    "block_group = %d, inode=%lu", group, ino);
		err = -EIO;
		goto fail;
	}

	BUFFER_TRACE(bh2, "get_write_access");
	err = ext3_journal_get_write_access(handle, bh2);
	if (err) goto fail;
	spin_lock(sb_bgl_lock(sbi, group));
	le16_add_cpu(&gdp->bg_free_inodes_count, -1);
	if (S_ISDIR(mode)) {
		le16_add_cpu(&gdp->bg_used_dirs_count, 1);
	}
	spin_unlock(sb_bgl_lock(sbi, group));
	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
	err = ext3_journal_dirty_metadata(handle, bh2);
	if (err) goto fail;

	percpu_counter_dec(&sbi->s_freeinodes_counter);
	if (S_ISDIR(mode))
		percpu_counter_inc(&sbi->s_dirs_counter);


	if (test_opt(sb, GRPID)) {
		inode->i_mode = mode;
		inode->i_uid = current_fsuid();
		inode->i_gid = dir->i_gid;
	} else
		inode_init_owner(inode, dir, mode);

	inode->i_ino = ino;
	/* This is the optimal IO size (for stat), not the fs block size */
	inode->i_blocks = 0;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;

	memset(ei->i_data, 0, sizeof(ei->i_data));
	ei->i_dir_start_lookup = 0;
	ei->i_disksize = 0;

	ei->i_flags =
		ext3_mask_flags(mode, EXT3_I(dir)->i_flags & EXT3_FL_INHERITED);
#ifdef EXT3_FRAGMENTS
	ei->i_faddr = 0;
	ei->i_frag_no = 0;
	ei->i_frag_size = 0;
#endif
	ei->i_file_acl = 0;
	ei->i_dir_acl = 0;
	ei->i_dtime = 0;
	ei->i_block_alloc_info = NULL;
	ei->i_block_group = group;

	ext3_set_inode_flags(inode);
	if (IS_DIRSYNC(inode))
		handle->h_sync = 1;
	if (insert_inode_locked(inode) < 0) {
		err = -EINVAL;
		goto fail_drop;
	}
	spin_lock(&sbi->s_next_gen_lock);
	inode->i_generation = sbi->s_next_generation++;
	spin_unlock(&sbi->s_next_gen_lock);

	ei->i_state_flags = 0;
	ext3_set_inode_state(inode, EXT3_STATE_NEW);

	/* See comment in ext3_iget for explanation */
	if (ino >= EXT3_FIRST_INO(sb) + 1 &&
	    EXT3_INODE_SIZE(sb) > EXT3_GOOD_OLD_INODE_SIZE) {
		ei->i_extra_isize =
			sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE;
	} else {
		ei->i_extra_isize = 0;
	}

	ret = inode;
	dquot_initialize(inode);
	err = dquot_alloc_inode(inode);
	if (err)
		goto fail_drop;

	err = ext3_init_acl(handle, inode, dir);
	if (err)
		goto fail_free_drop;

	err = ext3_init_security(handle, inode, dir, qstr);
	if (err)
		goto fail_free_drop;

	err = ext3_mark_inode_dirty(handle, inode);
	if (err) {
		ext3_std_error(sb, err);
		goto fail_free_drop;
	}

	ext3_debug("allocating inode %lu\n", inode->i_ino);
	trace_ext3_allocate_inode(inode, dir, mode);
	goto really_out;
fail:
	ext3_std_error(sb, err);
out:
	iput(inode);
	ret = ERR_PTR(err);
really_out:
	brelse(bitmap_bh);
	return ret;

fail_free_drop:
	dquot_free_inode(inode);

fail_drop:
	dquot_drop(inode);
	inode->i_flags |= S_NOQUOTA;
	inode->i_nlink = 0;
	unlock_new_inode(inode);
	iput(inode);
	brelse(bitmap_bh);
	return ERR_PTR(err);
}
示例#27
0
static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                        struct inode * new_dir,	struct dentry * new_dentry )
{
    struct inode * old_inode = old_dentry->d_inode;
    struct inode * new_inode = new_dentry->d_inode;
    struct page * dir_page = NULL;
    struct ext2_dir_entry_2 * dir_de = NULL;
    struct page * old_page;
    struct ext2_dir_entry_2 * old_de;
    int err = -ENOENT;

    dquot_initialize(old_dir);
    dquot_initialize(new_dir);

    old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page);
    if (!old_de)
        goto out;

    if (S_ISDIR(old_inode->i_mode)) {
        err = -EIO;
        dir_de = ext2_dotdot(old_inode, &dir_page);
        if (!dir_de)
            goto out_old;
    }

    if (new_inode) {
        struct page *new_page;
        struct ext2_dir_entry_2 *new_de;

        err = -ENOTEMPTY;
        if (dir_de && !ext2_empty_dir (new_inode))
            goto out_dir;

        err = -ENOENT;
        new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
        if (!new_de)
            goto out_dir;
        ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
        new_inode->i_ctime = CURRENT_TIME_SEC;
        if (dir_de)
            drop_nlink(new_inode);
        inode_dec_link_count(new_inode);
    } else {
        err = ext2_add_link(new_dentry, old_inode);
        if (err)
            goto out_dir;
        if (dir_de)
            inode_inc_link_count(new_dir);
    }

    /*
     * Like most other Unix systems, set the ctime for inodes on a
     * rename.
     */
    old_inode->i_ctime = CURRENT_TIME_SEC;
    mark_inode_dirty(old_inode);

    ext2_delete_entry (old_de, old_page);

    if (dir_de) {
        if (old_dir != new_dir)
            ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
        else {
            kunmap(dir_page);
            page_cache_release(dir_page);
        }
        inode_dec_link_count(old_dir);
    }
    return 0;


out_dir:
    if (dir_de) {
        kunmap(dir_page);
        page_cache_release(dir_page);
    }
out_old:
    kunmap(old_page);
    page_cache_release(old_page);
out:
    return err;
}
示例#28
0
/*
 * NAME:	jfs_unlink(dip, dentry)
 *
 * FUNCTION:	remove a link to object <vp> named by <name>
 *		from parent directory <dvp>
 *
 * PARAMETER:	dip	- inode of parent directory
 *		dentry	- dentry of object to be removed
 *
 * RETURN:	errors from subroutines
 *
 * note:
 * temporary file: if one or more processes have the file open
 * when the last link is removed, the link will be removed before
 * unlink() returns, but the removal of the file contents will be
 * postponed until all references to the files are closed.
 *
 * JFS does NOT support unlink() on directories.
 *
 */
static int jfs_unlink(struct inode *dip, struct dentry *dentry)
{
    int rc;
    tid_t tid;		/* transaction id */
    struct inode *ip = dentry->d_inode;
    ino_t ino;
    struct component_name dname;	/* object name */
    struct inode *iplist[2];
    struct tblock *tblk;
    s64 new_size = 0;
    int commit_flag;

    jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);

    /* Init inode for quota operations. */
    dquot_initialize(dip);
    dquot_initialize(ip);

    if ((rc = get_UCSname(&dname, dentry)))
        goto out;

    IWRITE_LOCK(ip, RDWRLOCK_NORMAL);

    tid = txBegin(dip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    iplist[0] = dip;
    iplist[1] = ip;

    /*
     * delete the entry of target file from parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
        jfs_err("jfs_unlink: dtDelete returned %d", rc);
        if (rc == -EIO)
            txAbort(tid, 1);	/* Marks FS Dirty */
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
        mutex_unlock(&JFS_IP(dip)->commit_mutex);
        IWRITE_UNLOCK(ip);
        goto out1;
    }

    ASSERT(ip->i_nlink);

    ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dip);

    /* update target's inode */
    inode_dec_link_count(ip);

    /*
     *	commit zero link count object
     */
    if (ip->i_nlink == 0) {
        assert(!test_cflag(COMMIT_Nolink, ip));
        /* free block resources */
        if ((new_size = commitZeroLink(tid, ip)) < 0) {
            txAbort(tid, 1);	/* Marks FS Dirty */
            txEnd(tid);
            mutex_unlock(&JFS_IP(ip)->commit_mutex);
            mutex_unlock(&JFS_IP(dip)->commit_mutex);
            IWRITE_UNLOCK(ip);
            rc = new_size;
            goto out1;
        }
        tblk = tid_to_tblock(tid);
        tblk->xflag |= COMMIT_DELETE;
        tblk->u.ip = ip;
    }

    /*
     * Incomplete truncate of file data can
     * result in timing problems unless we synchronously commit the
     * transaction.
     */
    if (new_size)
        commit_flag = COMMIT_SYNC;
    else
        commit_flag = 0;

    /*
     * If xtTruncate was incomplete, commit synchronously to avoid
     * timing complications
     */
    rc = txCommit(tid, 2, &iplist[0], commit_flag);

    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);

    while (new_size && (rc == 0)) {
        tid = txBegin(dip->i_sb, 0);
        mutex_lock(&JFS_IP(ip)->commit_mutex);
        new_size = xtTruncate_pmap(tid, ip, new_size);
        if (new_size < 0) {
            txAbort(tid, 1);	/* Marks FS Dirty */
            rc = new_size;
        } else
            rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
    }

    if (ip->i_nlink == 0)
        set_cflag(COMMIT_Nolink, ip);

    IWRITE_UNLOCK(ip);

    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, dip)) {
        if (dip->i_size > 1)
            jfs_truncate_nolock(dip, 0);

        clear_cflag(COMMIT_Stale, dip);
    }

out1:
    free_UCSname(&dname);
out:
    jfs_info("jfs_unlink: rc:%d", rc);
    return rc;
}
示例#29
0
/*
 * NAME:	jfs_rename
 *
 * FUNCTION:	rename a file or directory
 */
static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
{
    struct btstack btstack;
    ino_t ino;
    struct component_name new_dname;
    struct inode *new_ip;
    struct component_name old_dname;
    struct inode *old_ip;
    int rc;
    tid_t tid;
    struct tlock *tlck;
    struct dt_lock *dtlck;
    struct lv *lv;
    int ipcount;
    struct inode *iplist[4];
    struct tblock *tblk;
    s64 new_size = 0;
    int commit_flag;


    jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
             new_dentry->d_name.name);

    dquot_initialize(old_dir);
    dquot_initialize(new_dir);

    old_ip = old_dentry->d_inode;
    new_ip = new_dentry->d_inode;

    if ((rc = get_UCSname(&old_dname, old_dentry)))
        goto out1;

    if ((rc = get_UCSname(&new_dname, new_dentry)))
        goto out2;

    /*
     * Make sure source inode number is what we think it is
     */
    rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
    if (rc || (ino != old_ip->i_ino)) {
        rc = -ENOENT;
        goto out3;
    }

    /*
     * Make sure dest inode number (if any) is what we think it is
     */
    rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
    if (!rc) {
        if ((!new_ip) || (ino != new_ip->i_ino)) {
            rc = -ESTALE;
            goto out3;
        }
    } else if (rc != -ENOENT)
        goto out3;
    else if (new_ip) {
        /* no entry exists, but one was expected */
        rc = -ESTALE;
        goto out3;
    }

    if (S_ISDIR(old_ip->i_mode)) {
        if (new_ip) {
            if (!dtEmpty(new_ip)) {
                rc = -ENOTEMPTY;
                goto out3;
            }
        } else if ((new_dir != old_dir) &&
                   (new_dir->i_nlink == JFS_LINK_MAX)) {
            rc = -EMLINK;
            goto out3;
        }
    } else if (new_ip) {
        IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
        /* Init inode for quota operations. */
        dquot_initialize(new_ip);
    }

    /*
     * The real work starts here
     */
    tid = txBegin(new_dir->i_sb, 0);

    /*
     * How do we know the locking is safe from deadlocks?
     * The vfs does the hard part for us.  Any time we are taking nested
     * commit_mutexes, the vfs already has i_mutex held on the parent.
     * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
     */
    mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
    if (old_dir != new_dir)
        mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
                          COMMIT_MUTEX_SECOND_PARENT);

    if (new_ip) {
        mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
                          COMMIT_MUTEX_VICTIM);
        /*
         * Change existing directory entry to new inode number
         */
        ino = new_ip->i_ino;
        rc = dtModify(tid, new_dir, &new_dname, &ino,
                      old_ip->i_ino, JFS_RENAME);
        if (rc)
            goto out4;
        drop_nlink(new_ip);
        if (S_ISDIR(new_ip->i_mode)) {
            drop_nlink(new_ip);
            if (new_ip->i_nlink) {
                mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
                if (old_dir != new_dir)
                    mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
                mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
                mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
                if (!S_ISDIR(old_ip->i_mode) && new_ip)
                    IWRITE_UNLOCK(new_ip);
                jfs_error(new_ip->i_sb,
                          "jfs_rename: new_ip->i_nlink != 0");
                return -EIO;
            }
            tblk = tid_to_tblock(tid);
            tblk->xflag |= COMMIT_DELETE;
            tblk->u.ip = new_ip;
        } else if (new_ip->i_nlink == 0) {
            assert(!test_cflag(COMMIT_Nolink, new_ip));
            /* free block resources */
            if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
                txAbort(tid, 1);	/* Marks FS Dirty */
                rc = new_size;
                goto out4;
            }
            tblk = tid_to_tblock(tid);
            tblk->xflag |= COMMIT_DELETE;
            tblk->u.ip = new_ip;
        } else {
            new_ip->i_ctime = CURRENT_TIME;
            mark_inode_dirty(new_ip);
        }
    } else {
        /*
         * Add new directory entry
         */
        rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
                      JFS_CREATE);
        if (rc) {
            jfs_err("jfs_rename didn't expect dtSearch to fail "
                    "w/rc = %d", rc);
            goto out4;
        }

        ino = old_ip->i_ino;
        rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
        if (rc) {
            if (rc == -EIO)
                jfs_err("jfs_rename: dtInsert returned -EIO");
            goto out4;
        }
        if (S_ISDIR(old_ip->i_mode))
            inc_nlink(new_dir);
    }
    /*
     * Remove old directory entry
     */

    ino = old_ip->i_ino;
    rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
    if (rc) {
        jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
                rc);
        txAbort(tid, 1);	/* Marks Filesystem dirty */
        goto out4;
    }
    if (S_ISDIR(old_ip->i_mode)) {
        drop_nlink(old_dir);
        if (old_dir != new_dir) {
            /*
             * Change inode number of parent for moved directory
             */

            JFS_IP(old_ip)->i_dtroot.header.idotdot =
                cpu_to_le32(new_dir->i_ino);

            /* Linelock header of dtree */
            tlck = txLock(tid, old_ip,
                          (struct metapage *) &JFS_IP(old_ip)->bxflag,
                          tlckDTREE | tlckBTROOT | tlckRELINK);
            dtlck = (struct dt_lock *) & tlck->lock;
            ASSERT(dtlck->index == 0);
            lv = & dtlck->lv[0];
            lv->offset = 0;
            lv->length = 1;
            dtlck->index++;
        }
    }

    /*
     * Update ctime on changed/moved inodes & mark dirty
     */
    old_ip->i_ctime = CURRENT_TIME;
    mark_inode_dirty(old_ip);

    new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
    mark_inode_dirty(new_dir);

    /* Build list of inodes modified by this transaction */
    ipcount = 0;
    iplist[ipcount++] = old_ip;
    if (new_ip)
        iplist[ipcount++] = new_ip;
    iplist[ipcount++] = old_dir;

    if (old_dir != new_dir) {
        iplist[ipcount++] = new_dir;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
    }

    /*
     * Incomplete truncate of file data can
     * result in timing problems unless we synchronously commit the
     * transaction.
     */
    if (new_size)
        commit_flag = COMMIT_SYNC;
    else
        commit_flag = 0;

    rc = txCommit(tid, ipcount, iplist, commit_flag);

out4:
    txEnd(tid);
    if (new_ip)
        mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
    if (old_dir != new_dir)
        mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
    mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
    mutex_unlock(&JFS_IP(new_dir)->commit_mutex);

    while (new_size && (rc == 0)) {
        tid = txBegin(new_ip->i_sb, 0);
        mutex_lock(&JFS_IP(new_ip)->commit_mutex);
        new_size = xtTruncate_pmap(tid, new_ip, new_size);
        if (new_size < 0) {
            txAbort(tid, 1);
            rc = new_size;
        } else
            rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
        txEnd(tid);
        mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
    }
    if (new_ip && (new_ip->i_nlink == 0))
        set_cflag(COMMIT_Nolink, new_ip);
out3:
    free_UCSname(&new_dname);
out2:
    free_UCSname(&old_dname);
out1:
    if (new_ip && !S_ISDIR(new_ip->i_mode))
        IWRITE_UNLOCK(new_ip);
    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, old_dir)) {
        if (old_dir->i_size > 1)
            jfs_truncate_nolock(old_dir, 0);

        clear_cflag(COMMIT_Stale, old_dir);
    }

    jfs_info("jfs_rename: returning %d", rc);
    return rc;
}
示例#30
0
/*
 * NAME:	jfs_create(dip, dentry, mode)
 *
 * FUNCTION:	create a regular file in the parent directory <dip>
 *		with name = <from dentry> and mode = <mode>
 *
 * PARAMETER:	dip	- parent directory vnode
 *		dentry	- dentry of new file
 *		mode	- create mode (rwxrwxrwx).
 *		nd- nd struct
 *
 * RETURN:	Errors from subroutines
 *
 */
static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
                      struct nameidata *nd)
{
    int rc = 0;
    tid_t tid;		/* transaction id */
    struct inode *ip = NULL;	/* child directory inode */
    ino_t ino;
    struct component_name dname;	/* child directory name */
    struct btstack btstack;
    struct inode *iplist[2];
    struct tblock *tblk;

    jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);

    dquot_initialize(dip);

    /*
     * search parent directory for entry/freespace
     * (dtSearch() returns parent directory page pinned)
     */
    if ((rc = get_UCSname(&dname, dentry)))
        goto out1;

    /*
     * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
     * block there while holding dtree page, so we allocate the inode &
     * begin the transaction before we search the directory.
     */
    ip = ialloc(dip, mode);
    if (IS_ERR(ip)) {
        rc = PTR_ERR(ip);
        goto out2;
    }

    tid = txBegin(dip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    rc = jfs_init_acl(tid, ip, dip);
    if (rc)
        goto out3;

    rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
    if (rc) {
        txAbort(tid, 0);
        goto out3;
    }

    if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
        jfs_err("jfs_create: dtSearch returned %d", rc);
        txAbort(tid, 0);
        goto out3;
    }

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_CREATE;
    tblk->ino = ip->i_ino;
    tblk->u.ixpxd = JFS_IP(ip)->ixpxd;

    iplist[0] = dip;
    iplist[1] = ip;

    /*
     * initialize the child XAD tree root in-line in inode
     */
    xtInitRoot(tid, ip);

    /*
     * create entry in parent directory for child directory
     * (dtInsert() releases parent directory page)
     */
    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
        if (rc == -EIO) {
            jfs_err("jfs_create: dtInsert returned -EIO");
            txAbort(tid, 1);	/* Marks Filesystem dirty */
        } else
            txAbort(tid, 0);	/* Filesystem full */
        goto out3;
    }

    ip->i_op = &jfs_file_inode_operations;
    ip->i_fop = &jfs_file_operations;
    ip->i_mapping->a_ops = &jfs_aops;

    mark_inode_dirty(ip);

    dip->i_ctime = dip->i_mtime = CURRENT_TIME;

    mark_inode_dirty(dip);

    rc = txCommit(tid, 2, &iplist[0], 0);

out3:
    txEnd(tid);
    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);
    if (rc) {
        free_ea_wmap(ip);
        ip->i_nlink = 0;
        unlock_new_inode(ip);
        iput(ip);
    } else {
        d_instantiate(dentry, ip);
        unlock_new_inode(ip);
    }

out2:
    free_UCSname(&dname);

out1:

    jfs_info("jfs_create: rc:%d", rc);
    return rc;
}