Ejemplo n.º 1
0
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                             unsigned int mode, dev_t dev, const char *symname,
                             unsigned int size)
{
    const struct qstr *name = &dentry->d_name;
    struct gfs2_holder ghs[2];
    struct inode *inode = NULL;
    struct gfs2_inode *dip = GFS2_I(dir);
    struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
    struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
    int error;
    u64 generation;
    struct buffer_head *bh = NULL;

    if (!name->len || name->len > GFS2_FNAMESIZE)
        return -ENAMETOOLONG;

    error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
    if (error)
        goto fail;

    error = create_ok(dip, name, mode);
    if (error)
        goto fail_gunlock;

    error = alloc_dinode(dip, &inum.no_addr, &generation);
    if (error)
        goto fail_gunlock;
    inum.no_formal_ino = generation;

    error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
                              LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
    if (error)
        goto fail_gunlock;

    error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, symname, size, &bh);
    if (error)
        goto fail_gunlock2;

    inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
                              inum.no_formal_ino, 0);
    if (IS_ERR(inode))
        goto fail_gunlock2;

    error = gfs2_inode_refresh(GFS2_I(inode));
    if (error)
        goto fail_gunlock2;

    error = gfs2_acl_create(dip, inode);
    if (error)
        goto fail_gunlock2;

    error = gfs2_security_init(dip, GFS2_I(inode), name);
    if (error)
        goto fail_gunlock2;

    error = link_dinode(dip, name, GFS2_I(inode));
    if (error)
        goto fail_gunlock2;

    if (bh)
        brelse(bh);

    gfs2_trans_end(sdp);
    if (dip->i_alloc->al_rgd)
        gfs2_inplace_release(dip);
    gfs2_quota_unlock(dip);
    gfs2_alloc_put(dip);
    gfs2_glock_dq_uninit_m(2, ghs);
    mark_inode_dirty(inode);
    d_instantiate(dentry, inode);
    return 0;

fail_gunlock2:
    gfs2_glock_dq_uninit(ghs + 1);
    if (inode && !IS_ERR(inode))
        iput(inode);
fail_gunlock:
    gfs2_glock_dq_uninit(ghs);
fail:
    if (bh)
        brelse(bh);
    return error;
}

/**
 * gfs2_create - Create a file
 * @dir: The directory in which to create the file
 * @dentry: The dentry of the new file
 * @mode: The mode of the new file
 *
 * Returns: errno
 */

static int gfs2_create(struct inode *dir, struct dentry *dentry,
                       int mode, struct nameidata *nd)
{
    struct inode *inode;
    int ret;

    for (;;) {
        ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
        if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
            return ret;

        inode = gfs2_lookupi(dir, &dentry->d_name, 0);
        if (inode) {
            if (!IS_ERR(inode))
                break;
            return PTR_ERR(inode);
        }
    }

    d_instantiate(dentry, inode);
    return 0;
}

/**
 * gfs2_lookup - Look up a filename in a directory and return its inode
 * @dir: The directory inode
 * @dentry: The dentry of the new inode
 * @nd: passed from Linux VFS, ignored by us
 *
 * Called by the VFS layer. Lock dir and call gfs2_lookupi()
 *
 * Returns: errno
 */

static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
                                  struct nameidata *nd)
{
    struct inode *inode = NULL;

    inode = gfs2_lookupi(dir, &dentry->d_name, 0);
    if (inode && IS_ERR(inode))
        return ERR_CAST(inode);

    if (inode) {
        struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
        struct gfs2_holder gh;
        int error;
        error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
        if (error) {
            iput(inode);
            return ERR_PTR(error);
        }
        gfs2_glock_dq_uninit(&gh);
        return d_splice_alias(inode, dentry);
    }
    d_add(dentry, inode);

    return NULL;
}

/**
 * gfs2_link - Link to a file
 * @old_dentry: The inode to link
 * @dir: Add link to this directory
 * @dentry: The name of the link
 *
 * Link the inode in "old_dentry" into the directory "dir" with the
 * name in "dentry".
 *
 * Returns: errno
 */

static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
                     struct dentry *dentry)
{
    struct gfs2_inode *dip = GFS2_I(dir);
    struct gfs2_sbd *sdp = GFS2_SB(dir);
    struct inode *inode = old_dentry->d_inode;
    struct gfs2_inode *ip = GFS2_I(inode);
    struct gfs2_holder ghs[2];
    struct buffer_head *dibh;
    int alloc_required;
    int error;

    if (S_ISDIR(inode->i_mode))
        return -EPERM;

    gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
    gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);

    error = gfs2_glock_nq(ghs); /* parent */
    if (error)
        goto out_parent;

    error = gfs2_glock_nq(ghs + 1); /* child */
    if (error)
        goto out_child;

    error = -ENOENT;
    if (inode->i_nlink == 0)
        goto out_gunlock;

    error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0);
    if (error)
        goto out_gunlock;

    error = gfs2_dir_check(dir, &dentry->d_name, NULL);
    switch (error) {
    case -ENOENT:
        break;
    case 0:
        error = -EEXIST;
    default:
        goto out_gunlock;
    }

    error = -EINVAL;
    if (!dip->i_inode.i_nlink)
        goto out_gunlock;
    error = -EFBIG;
    if (dip->i_entries == (u32)-1)
        goto out_gunlock;
    error = -EPERM;
    if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
        goto out_gunlock;
    error = -EINVAL;
    if (!ip->i_inode.i_nlink)
        goto out_gunlock;
    error = -EMLINK;
    if (ip->i_inode.i_nlink == (u32)-1)
        goto out_gunlock;

    alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
    if (error < 0)
        goto out_gunlock;
    error = 0;

    if (alloc_required) {
        struct gfs2_alloc *al = gfs2_alloc_get(dip);
        if (!al) {
            error = -ENOMEM;
            goto out_gunlock;
        }

        error = gfs2_quota_lock_check(dip);
        if (error)
            goto out_alloc;

        al->al_requested = sdp->sd_max_dirres;

        error = gfs2_inplace_reserve(dip);
        if (error)
            goto out_gunlock_q;

        error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
                                 gfs2_rg_blocks(al) +
                                 2 * RES_DINODE + RES_STATFS +
                                 RES_QUOTA, 0);
        if (error)
            goto out_ipres;
    } else {
        error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
        if (error)
            goto out_ipres;
    }

    error = gfs2_meta_inode_buffer(ip, &dibh);
    if (error)
        goto out_end_trans;

    error = gfs2_dir_add(dir, &dentry->d_name, ip);
    if (error)
        goto out_brelse;

    gfs2_trans_add_bh(ip->i_gl, dibh, 1);
    inc_nlink(&ip->i_inode);
    ip->i_inode.i_ctime = CURRENT_TIME;
    gfs2_dinode_out(ip, dibh->b_data);
    mark_inode_dirty(&ip->i_inode);

out_brelse:
    brelse(dibh);
out_end_trans:
    gfs2_trans_end(sdp);
out_ipres:
    if (alloc_required)
        gfs2_inplace_release(dip);
out_gunlock_q:
    if (alloc_required)
        gfs2_quota_unlock(dip);
out_alloc:
    if (alloc_required)
        gfs2_alloc_put(dip);
out_gunlock:
    gfs2_glock_dq(ghs + 1);
out_child:
    gfs2_glock_dq(ghs);
out_parent:
    gfs2_holder_uninit(ghs);
    gfs2_holder_uninit(ghs + 1);
    if (!error) {
        ihold(inode);
        d_instantiate(dentry, inode);
        mark_inode_dirty(inode);
    }
    return error;
}

/*
 * gfs2_unlink_ok - check to see that a inode is still in a directory
 * @dip: the directory
 * @name: the name of the file
 * @ip: the inode
 *
 * Assumes that the lock on (at least) @dip is held.
 *
 * Returns: 0 if the parent/child relationship is correct, errno if it isn't
 */

static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
                          const struct gfs2_inode *ip)
{
    int error;

    if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
        return -EPERM;

    if ((dip->i_inode.i_mode & S_ISVTX) &&
            dip->i_inode.i_uid != current_fsuid() &&
            ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
        return -EPERM;

    if (IS_APPEND(&dip->i_inode))
        return -EPERM;

    error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0);
    if (error)
        return error;

    error = gfs2_dir_check(&dip->i_inode, name, ip);
    if (error)
        return error;

    return 0;
}
Ejemplo n.º 2
0
/* Get a block at iblock for inode, possibly allocating if create */
int hfsplus_get_block(struct inode *inode, sector_t iblock,
		      struct buffer_head *bh_result, int create)
{
	struct super_block *sb = inode->i_sb;
	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
	int res = -EIO;
	u32 ablock, dblock, mask;
	sector_t sector;
	int was_dirty = 0;
	int shift;

	/* Convert inode block to disk allocation block */
	shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
	ablock = iblock >> sbi->fs_shift;

	if (iblock >= hip->fs_blocks) {
		if (iblock > hip->fs_blocks || !create)
			return -EIO;
		if (ablock >= hip->alloc_blocks) {
			res = hfsplus_file_extend(inode);
			if (res)
				return res;
		}
	} else
		create = 0;

	if (ablock < hip->first_blocks) {
		dblock = hfsplus_ext_find_block(hip->first_extents, ablock);
		goto done;
	}

	if (inode->i_ino == HFSPLUS_EXT_CNID)
		return -EIO;

	mutex_lock(&hip->extents_lock);

	/*
	 * hfsplus_ext_read_extent will write out a cached extent into
	 * the extents btree.  In that case we may have to mark the inode
	 * dirty even for a pure read of an extent here.
	 */
	was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY);
	res = hfsplus_ext_read_extent(inode, ablock);
	if (res) {
		mutex_unlock(&hip->extents_lock);
		return -EIO;
	}
	dblock = hfsplus_ext_find_block(hip->cached_extents,
					ablock - hip->cached_start);
	mutex_unlock(&hip->extents_lock);

done:
	hfs_dbg(EXTENT, "get_block(%lu): %llu - %u\n",
		inode->i_ino, (long long)iblock, dblock);

	mask = (1 << sbi->fs_shift) - 1;
	sector = ((sector_t)dblock << sbi->fs_shift) +
		  sbi->blockoffset + (iblock & mask);
	map_bh(bh_result, sb, sector);

	if (create) {
		set_buffer_new(bh_result);
		hip->phys_size += sb->s_blocksize;
		hip->fs_blocks++;
		inode_add_bytes(inode, sb->s_blocksize);
	}
	if (create || was_dirty)
		mark_inode_dirty(inode);
	return 0;
}
Ejemplo n.º 3
0
/*
 * inode->i_sem: down
 */
static int
ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
{
	struct ext2_inode_info *ei = EXT2_I(inode);
	int name_index;
	void *value = NULL;
	size_t size;
	int error;

	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;
	if (!test_opt(inode->i_sb, POSIX_ACL))
		return 0;

	switch(type) {
		case ACL_TYPE_ACCESS:
			name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
			if (acl) {
				mode_t mode = inode->i_mode;
				error = posix_acl_equiv_mode(acl, &mode);
				if (error < 0)
					return error;
				else {
					inode->i_mode = mode;
					mark_inode_dirty(inode);
					if (error == 0)
						acl = NULL;
				}
			}
			break;

		case ACL_TYPE_DEFAULT:
			name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
			if (!S_ISDIR(inode->i_mode))
				return acl ? -EACCES : 0;
			break;

		default:
			return -EINVAL;
	}
 	if (acl) {
		value = ext2_acl_to_disk(acl, &size);
		if (IS_ERR(value))
			return (int)PTR_ERR(value);
	}

	error = ext2_xattr_set(inode, name_index, "", value, size, 0);

	if (value)
		kfree(value);
	if (!error) {
		switch(type) {
			case ACL_TYPE_ACCESS:
				ext2_iset_acl(inode, &ei->i_acl, acl);
				break;

			case ACL_TYPE_DEFAULT:
				ext2_iset_acl(inode, &ei->i_default_acl, acl);
				break;
		}
	}
	return error;
}
Ejemplo n.º 4
0
static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
								int mode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct address_space *mapping = inode->i_mapping;
	pgoff_t index, pg_start, pg_end;
	loff_t new_size = i_size_read(inode);
	loff_t off_start, off_end;
	int ret = 0;

	ret = inode_newsize_ok(inode, (len + offset));
	if (ret)
		return ret;

	f2fs_balance_fs(sbi);

	if (f2fs_has_inline_data(inode)) {
		ret = f2fs_convert_inline_inode(inode);
		if (ret)
			return ret;
	}

	ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
	if (ret)
		return ret;

	truncate_pagecache_range(inode, offset, offset + len - 1);

	pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
	pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;

	off_start = offset & (PAGE_CACHE_SIZE - 1);
	off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);

	if (pg_start == pg_end) {
		ret = fill_zero(inode, pg_start, off_start,
						off_end - off_start);
		if (ret)
			return ret;

		if (offset + len > new_size)
			new_size = offset + len;
		new_size = max_t(loff_t, new_size, offset + len);
	} else {
		if (off_start) {
			ret = fill_zero(inode, pg_start++, off_start,
						PAGE_CACHE_SIZE - off_start);
			if (ret)
				return ret;

			new_size = max_t(loff_t, new_size,
					(loff_t)pg_start << PAGE_CACHE_SHIFT);
		}

		for (index = pg_start; index < pg_end; index++) {
			struct dnode_of_data dn;
			struct page *ipage;

			f2fs_lock_op(sbi);

			ipage = get_node_page(sbi, inode->i_ino);
			if (IS_ERR(ipage)) {
				ret = PTR_ERR(ipage);
				f2fs_unlock_op(sbi);
				goto out;
			}

			set_new_dnode(&dn, inode, ipage, NULL, 0);
			ret = f2fs_reserve_block(&dn, index);
			if (ret) {
				f2fs_unlock_op(sbi);
				goto out;
			}

			if (dn.data_blkaddr != NEW_ADDR) {
				invalidate_blocks(sbi, dn.data_blkaddr);

				dn.data_blkaddr = NEW_ADDR;
				set_data_blkaddr(&dn);

				dn.data_blkaddr = NULL_ADDR;
				f2fs_update_extent_cache(&dn);
			}
			f2fs_put_dnode(&dn);
			f2fs_unlock_op(sbi);

			new_size = max_t(loff_t, new_size,
				(loff_t)(index + 1) << PAGE_CACHE_SHIFT);
		}

		if (off_end) {
			ret = fill_zero(inode, pg_end, 0, off_end);
			if (ret)
				goto out;

			new_size = max_t(loff_t, new_size, offset + len);
		}
	}

out:
	if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) {
		i_size_write(inode, new_size);
		mark_inode_dirty(inode);
		update_inode_page(inode);
	}

	return ret;
}
Ejemplo n.º 5
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, umode_t mode,
		bool excl)
{
	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);
		clear_nlink(ip);
		unlock_new_inode(ip);
		iput(ip);
	} else {
		unlock_new_inode(ip);
		d_instantiate(dentry, ip);
	}

      out2:
	free_UCSname(&dname);

      out1:

	jfs_info("jfs_create: rc:%d", rc);
	return rc;
}
Ejemplo n.º 6
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 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;
		}
		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);
		clear_nlink(ip);
		unlock_new_inode(ip);
		iput(ip);
	} else {
		unlock_new_inode(ip);
		d_instantiate(dentry, ip);
	}

      out2:
	free_UCSname(&dname);

      out1:
	jfs_info("jfs_symlink: rc:%d", rc);
	return rc;
}
Ejemplo n.º 7
0
struct dentry *f2fs_get_parent(struct dentry *child)
{
    struct qstr dotdot = {.len = 2, .name = ".."};
    unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot);
    if (!ino)
        return ERR_PTR(-ENOENT);
    return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino));
}

static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                                  struct nameidata *nd)
{
    struct inode *inode = NULL;
    struct f2fs_dir_entry *de;
    struct page *page;

    if (dentry->d_name.len > F2FS_NAME_LEN)
        return ERR_PTR(-ENAMETOOLONG);

    de = f2fs_find_entry(dir, &dentry->d_name, &page);
    if (de) {
        nid_t ino = le32_to_cpu(de->ino);
        kunmap(page);
        f2fs_put_page(page, 0);

        inode = f2fs_iget(dir->i_sb, ino);
        if (IS_ERR(inode))
            return ERR_CAST(inode);

        stat_inc_inline_inode(inode);
    }

    return d_splice_alias(inode, dentry);
}

static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode = dentry->d_inode;
    struct f2fs_dir_entry *de;
    struct page *page;
    int err = -ENOENT;

    trace_f2fs_unlink_enter(dir, dentry);
    f2fs_balance_fs(sbi);

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

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

    /* In order to evict this inode, we set it dirty */
    mark_inode_dirty(inode);
fail:
    trace_f2fs_unlink_exit(inode, err);
    return err;
}

static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                        const char *symname)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    size_t symlen = strlen(symname) + 1;
    int err;

    f2fs_balance_fs(sbi);

    inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
    if (IS_ERR(inode))
        return PTR_ERR(inode);

    inode->i_op = &f2fs_symlink_inode_operations;
    inode->i_mapping->a_ops = &f2fs_dblock_aops;

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

    err = page_symlink(inode, symname, symlen);
    alloc_nid_done(sbi, inode->i_ino);

    d_instantiate(dentry, inode);
    unlock_new_inode(inode);
    return err;
out:
    clear_nlink(inode);
    iget_failed(inode);
    alloc_nid_failed(sbi, inode->i_ino);
    return err;
}

static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    int err;

    f2fs_balance_fs(sbi);

    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_ZERO);

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

    alloc_nid_done(sbi, inode->i_ino);

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

    return 0;

out_fail:
    clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
    clear_nlink(inode);
    iget_failed(inode);
    alloc_nid_failed(sbi, inode->i_ino);
    return err;
}

static int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
{
    struct inode *inode = dentry->d_inode;
    if (f2fs_empty_dir(inode))
        return f2fs_unlink(dir, dentry);
    return -ENOTEMPTY;
}

static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
                      int mode, dev_t rdev)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    int err = 0;

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

    f2fs_balance_fs(sbi);

    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);
    f2fs_unlock_op(sbi);
    if (err)
        goto out;

    alloc_nid_done(sbi, inode->i_ino);
    d_instantiate(dentry, inode);
    unlock_new_inode(inode);
    return 0;
out:
    clear_nlink(inode);
    iget_failed(inode);
    alloc_nid_failed(sbi, inode->i_ino);
    return err;
}

static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                       struct inode *new_dir, struct dentry *new_dentry)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
    struct inode *old_inode = old_dentry->d_inode;
    struct inode *new_inode = new_dentry->d_inode;
    struct page *old_dir_page;
    struct page *old_page, *new_page;
    struct f2fs_dir_entry *old_dir_entry = NULL;
    struct f2fs_dir_entry *old_entry;
    struct f2fs_dir_entry *new_entry;
    int err = -ENOENT;

    f2fs_balance_fs(sbi);

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

    if (S_ISDIR(old_inode->i_mode)) {
        err = -EIO;
        old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
        if (!old_dir_entry)
            goto out_old;
    }

    if (new_inode) {

        err = -ENOTEMPTY;
        if (old_dir_entry && !f2fs_empty_dir(new_inode))
            goto out_dir;

        err = -ENOENT;
        new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
                                    &new_page);
        if (!new_entry)
            goto out_dir;

        f2fs_lock_op(sbi);

        err = acquire_orphan_inode(sbi);
        if (err)
            goto put_out_dir;

        if (update_dent_inode(old_inode, &new_dentry->d_name)) {
            release_orphan_inode(sbi);
            goto put_out_dir;
        }

        f2fs_set_link(new_dir, new_entry, new_page, old_inode);

        new_inode->i_ctime = CURRENT_TIME;
        down_write(&F2FS_I(new_inode)->i_sem);
        if (old_dir_entry)
            drop_nlink(new_inode);
        drop_nlink(new_inode);
        up_write(&F2FS_I(new_inode)->i_sem);

        mark_inode_dirty(new_inode);

        if (!new_inode->i_nlink)
            add_orphan_inode(sbi, new_inode->i_ino);
        else
            release_orphan_inode(sbi);

        update_inode_page(old_inode);
        update_inode_page(new_inode);
    } else {
        f2fs_lock_op(sbi);

        err = f2fs_add_link(new_dentry, old_inode);
        if (err) {
            f2fs_unlock_op(sbi);
            goto out_dir;
        }

        if (old_dir_entry) {
            inc_nlink(new_dir);
            update_inode_page(new_dir);
        }
    }

    down_write(&F2FS_I(old_inode)->i_sem);
    file_lost_pino(old_inode);
    up_write(&F2FS_I(old_inode)->i_sem);

    old_inode->i_ctime = CURRENT_TIME;
    mark_inode_dirty(old_inode);

    f2fs_delete_entry(old_entry, old_page, NULL);

    if (old_dir_entry) {
        if (old_dir != new_dir) {
            f2fs_set_link(old_inode, old_dir_entry,
                          old_dir_page, new_dir);
            update_inode_page(old_inode);
        } else {
            kunmap(old_dir_page);
            f2fs_put_page(old_dir_page, 0);
        }
        drop_nlink(old_dir);
        mark_inode_dirty(old_dir);
        update_inode_page(old_dir);
    }

    f2fs_unlock_op(sbi);
    return 0;

put_out_dir:
    f2fs_unlock_op(sbi);
    kunmap(new_page);
    f2fs_put_page(new_page, 0);
out_dir:
    if (old_dir_entry) {
        kunmap(old_dir_page);
        f2fs_put_page(old_dir_page, 0);
    }
out_old:
    kunmap(old_page);
    f2fs_put_page(old_page, 0);
out:
    return err;
}

const struct inode_operations f2fs_dir_inode_operations = {
    .create		= f2fs_create,
    .lookup		= f2fs_lookup,
    .link		= f2fs_link,
    .unlink		= f2fs_unlink,
    .symlink	= f2fs_symlink,
    .mkdir		= f2fs_mkdir,
    .rmdir		= f2fs_rmdir,
    .mknod		= f2fs_mknod,
    .rename		= f2fs_rename,
    .getattr	= f2fs_getattr,
    .setattr	= f2fs_setattr,
    .check_acl	= f2fs_check_acl,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr	= generic_setxattr,
    .getxattr	= generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_symlink_inode_operations = {
    .readlink       = generic_readlink,
    .follow_link    = page_follow_link_light,
    .put_link       = page_put_link,
    .getattr	= f2fs_getattr,
    .setattr	= f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr	= generic_setxattr,
    .getxattr	= generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_special_inode_operations = {
    .getattr	= f2fs_getattr,
    .setattr        = f2fs_setattr,
    .check_acl	= f2fs_check_acl,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr       = generic_setxattr,
    .getxattr       = generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr    = generic_removexattr,
#endif
};
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct gfs2_inode *dip = GFS2_I(dir), *ip;
	struct gfs2_sbd *sdp = GFS2_SB(dir);
	struct gfs2_holder ghs[2];
	struct inode *inode;
	struct buffer_head *dibh;
	int error;

	gfs2_holder_init(dip->i_gl, 0, 0, ghs);

	inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0);
	if (IS_ERR(inode)) {
		gfs2_holder_uninit(ghs);
		return PTR_ERR(inode);
	}

	ip = ghs[1].gh_gl->gl_object;

	ip->i_inode.i_nlink = 2;
	i_size_write(inode, sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode));
	ip->i_diskflags |= GFS2_DIF_JDATA;
	ip->i_entries = 2;

	error = gfs2_meta_inode_buffer(ip, &dibh);

	if (!gfs2_assert_withdraw(sdp, !error)) {
		struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
		struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);

		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
		gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent);
		dent->de_inum = di->di_num; /* already GFS2 endian */
		dent->de_type = cpu_to_be16(DT_DIR);
		di->di_entries = cpu_to_be32(1);

		dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
		gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);

		gfs2_inum_out(dip, dent);
		dent->de_type = cpu_to_be16(DT_DIR);

		gfs2_dinode_out(ip, di);

		brelse(dibh);
	}

	error = gfs2_change_nlink(dip, +1);
	gfs2_assert_withdraw(sdp, !error); /* dip already pinned */

	gfs2_trans_end(sdp);
	if (dip->i_alloc->al_rgd)
		gfs2_inplace_release(dip);
	gfs2_quota_unlock(dip);
	gfs2_alloc_put(dip);

	gfs2_glock_dq_uninit_m(2, ghs);

	d_instantiate(dentry, inode);
	mark_inode_dirty(inode);

	return 0;
}
Ejemplo n.º 10
0
Archivo: ioctl.c Proyecto: 274914765/C
int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
          unsigned long arg)
{
    unsigned int flags;

    switch (cmd) {
    case HFSPLUS_IOC_EXT2_GETFLAGS:
        flags = 0;
        if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
            flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
        if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
            flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
        if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
            flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
        return put_user(flags, (int __user *)arg);
    case HFSPLUS_IOC_EXT2_SETFLAGS: {
        int err = 0;
        err = mnt_want_write(filp->f_path.mnt);
        if (err)
            return err;

        if (!is_owner_or_cap(inode)) {
            err = -EACCES;
            goto setflags_out;
        }
        if (get_user(flags, (int __user *)arg)) {
            err = -EFAULT;
            goto setflags_out;
        }
        if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
            HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
            if (!capable(CAP_LINUX_IMMUTABLE)) {
                err = -EPERM;
                goto setflags_out;
            }
        }

        /* don't silently ignore unsupported ext2 flags */
        if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
            err = -EOPNOTSUPP;
            goto setflags_out;
        }
        if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */
            inode->i_flags |= S_IMMUTABLE;
            HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE;
        } else {
            inode->i_flags &= ~S_IMMUTABLE;
            HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
        }
        if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
            inode->i_flags |= S_APPEND;
            HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
        } else {
            inode->i_flags &= ~S_APPEND;
            HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
        }
        if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
            HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
        else
            HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;

        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
setflags_out:
        mnt_drop_write(filp->f_path.mnt);
        return err;
    }
    default:
        return -ENOTTY;
    }
}
Ejemplo n.º 11
0
static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
		     struct dentry *dentry)
{
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(dir);
	struct inode *inode = old_dentry->d_inode;
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_holder ghs[2];
	int alloc_required;
	int error;

	if (S_ISDIR(inode->i_mode))
		return -EPERM;

	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);

	error = gfs2_glock_nq(ghs); /* parent */
	if (error)
		goto out_parent;

	error = gfs2_glock_nq(ghs + 1); /* child */
	if (error)
		goto out_child;

	error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0);
	if (error)
		goto out_gunlock;

	error = gfs2_dir_check(dir, &dentry->d_name, NULL);
	switch (error) {
	case -ENOENT:
		break;
	case 0:
		error = -EEXIST;
	default:
		goto out_gunlock;
	}

	error = -EINVAL;
	if (!dip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EFBIG;
	if (dip->i_entries == (u32)-1)
		goto out_gunlock;
	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out_gunlock;
	error = -EINVAL;
	if (!ip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EMLINK;
	if (ip->i_inode.i_nlink == (u32)-1)
		goto out_gunlock;

	alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
	if (error < 0)
		goto out_gunlock;
	error = 0;

	if (alloc_required) {
		struct gfs2_alloc *al = gfs2_alloc_get(dip);
		if (!al) {
			error = -ENOMEM;
			goto out_gunlock;
		}

		error = gfs2_quota_lock_check(dip);
		if (error)
			goto out_alloc;

		al->al_requested = sdp->sd_max_dirres;

		error = gfs2_inplace_reserve(dip);
		if (error)
			goto out_gunlock_q;

		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
					 gfs2_rg_blocks(al) +
					 2 * RES_DINODE + RES_STATFS +
					 RES_QUOTA, 0);
		if (error)
			goto out_ipres;
	} else {
		error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
		if (error)
			goto out_ipres;
	}

	error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode));
	if (error)
		goto out_end_trans;

	error = gfs2_change_nlink(ip, +1);

out_end_trans:
	gfs2_trans_end(sdp);
out_ipres:
	if (alloc_required)
		gfs2_inplace_release(dip);
out_gunlock_q:
	if (alloc_required)
		gfs2_quota_unlock(dip);
out_alloc:
	if (alloc_required)
		gfs2_alloc_put(dip);
out_gunlock:
	gfs2_glock_dq(ghs + 1);
out_child:
	gfs2_glock_dq(ghs);
out_parent:
	gfs2_holder_uninit(ghs);
	gfs2_holder_uninit(ghs + 1);
	if (!error) {
		ihold(inode);
		d_instantiate(dentry, inode);
		mark_inode_dirty(inode);
	}
	return error;
}
Ejemplo n.º 12
0
int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
{
	struct hfs_btree *tree;
	struct hfs_bnode *node, *new_node;
	int size, key_len, rec;
	int data_off, end_off;
	int idx_rec_off, data_rec_off, end_rec_off;
	__be32 cnid;

	tree = fd->tree;
	if (!fd->bnode) {
		if (!tree->root)
			hfs_btree_inc_height(tree);
		fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
		if (IS_ERR(fd->bnode))
			return PTR_ERR(fd->bnode);
		fd->record = -1;
	}
	new_node = NULL;
	key_len = be16_to_cpu(fd->search_key->key_len) + 2;
again:
	/* new record idx and complete record size */
	rec = fd->record + 1;
	size = key_len + entry_len;

	node = fd->bnode;
	hfs_bnode_dump(node);
	/* get last offset */
	end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
	end_off = hfs_bnode_read_u16(node, end_rec_off);
	end_rec_off -= 2;
	hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
		rec, size, end_off, end_rec_off);
	if (size > end_rec_off - end_off) {
		if (new_node)
			panic("not enough room!\n");
		new_node = hfs_bnode_split(fd);
		if (IS_ERR(new_node))
			return PTR_ERR(new_node);
		goto again;
	}
	if (node->type == HFS_NODE_LEAF) {
		tree->leaf_count++;
		mark_inode_dirty(tree->inode);
	}
	node->num_recs++;
	/* write new last offset */
	hfs_bnode_write_u16(node,
		offsetof(struct hfs_bnode_desc, num_recs),
		node->num_recs);
	hfs_bnode_write_u16(node, end_rec_off, end_off + size);
	data_off = end_off;
	data_rec_off = end_rec_off + 2;
	idx_rec_off = tree->node_size - (rec + 1) * 2;
	if (idx_rec_off == data_rec_off)
		goto skip;
	/* move all following entries */
	do {
		data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
		hfs_bnode_write_u16(node, data_rec_off, data_off + size);
		data_rec_off += 2;
	} while (data_rec_off < idx_rec_off);

	/* move data away */
	hfs_bnode_move(node, data_off + size, data_off,
		       end_off - data_off);

skip:
	hfs_bnode_write(node, fd->search_key, data_off, key_len);
	hfs_bnode_write(node, entry, data_off + key_len, entry_len);
	hfs_bnode_dump(node);

	if (new_node) {
		/* update parent key if we inserted a key
		 * at the start of the first node
		 */
		if (!rec && new_node != node)
			hfs_brec_update_parent(fd);

		hfs_bnode_put(fd->bnode);
		if (!new_node->parent) {
			hfs_btree_inc_height(tree);
			new_node->parent = tree->root;
		}
		fd->bnode = hfs_bnode_find(tree, new_node->parent);

		/* create index data entry */
		cnid = cpu_to_be32(new_node->this);
		entry = &cnid;
		entry_len = sizeof(cnid);

		/* get index key */
		hfs_bnode_read_key(new_node, fd->search_key, 14);
		__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);

		hfs_bnode_put(new_node);
		new_node = NULL;

		if ((tree->attributes & HFS_TREE_VARIDXKEYS) ||
				(tree->cnid == HFSPLUS_ATTR_CNID))
			key_len = be16_to_cpu(fd->search_key->key_len) + 2;
		else {
			fd->search_key->key_len =
				cpu_to_be16(tree->max_key_len);
			key_len = tree->max_key_len + 2;
		}
		goto again;
	}

	if (!rec)
		hfs_brec_update_parent(fd);

	return 0;
}
Ejemplo n.º 13
0
void hfsplus_file_truncate(struct inode *inode)
{
	struct super_block *sb = inode->i_sb;
	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
	struct hfs_find_data fd;
	u32 alloc_cnt, blk_cnt, start;
	int res;

	hfs_dbg(INODE, "truncate: %lu, %llu -> %llu\n",
		inode->i_ino, (long long)hip->phys_size, inode->i_size);

	if (inode->i_size > hip->phys_size) {
		struct address_space *mapping = inode->i_mapping;
		struct page *page;
		void *fsdata;
		loff_t size = inode->i_size;

		res = pagecache_write_begin(NULL, mapping, size, 0,
						AOP_FLAG_UNINTERRUPTIBLE,
						&page, &fsdata);
		if (res)
			return;
		res = pagecache_write_end(NULL, mapping, size,
			0, 0, page, fsdata);
		if (res < 0)
			return;
		mark_inode_dirty(inode);
		return;
	} else if (inode->i_size == hip->phys_size)
		return;

	blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >>
			HFSPLUS_SB(sb)->alloc_blksz_shift;
	alloc_cnt = hip->alloc_blocks;
	if (blk_cnt == alloc_cnt)
		goto out;

	mutex_lock(&hip->extents_lock);
	res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
	if (res) {
		mutex_unlock(&hip->extents_lock);
		/* XXX: We lack error handling of hfsplus_file_truncate() */
		return;
	}
	while (1) {
		if (alloc_cnt == hip->first_blocks) {
			hfsplus_free_extents(sb, hip->first_extents,
					     alloc_cnt, alloc_cnt - blk_cnt);
			hfsplus_dump_extent(hip->first_extents);
			hip->first_blocks = blk_cnt;
			break;
		}
		res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt);
		if (res)
			break;
		start = hip->cached_start;
		hfsplus_free_extents(sb, hip->cached_extents,
				     alloc_cnt - start, alloc_cnt - blk_cnt);
		hfsplus_dump_extent(hip->cached_extents);
		if (blk_cnt > start) {
			hip->extent_state |= HFSPLUS_EXT_DIRTY;
			break;
		}
		alloc_cnt = start;
		hip->cached_start = hip->cached_blocks = 0;
		hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
		hfs_brec_remove(&fd);
	}
	hfs_find_exit(&fd);
	mutex_unlock(&hip->extents_lock);

	hip->alloc_blocks = blk_cnt;
out:
	hip->phys_size = inode->i_size;
	hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
		sb->s_blocksize_bits;
	inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
	hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
}
Ejemplo n.º 14
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_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;
}
Ejemplo n.º 15
0
static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
			   int mode)
{
	struct gfs2_inode *ip = GFS2_I(inode);
	struct buffer_head *dibh;
	int error;
	loff_t size = len;
	unsigned int nr_blks;
	sector_t lblock = offset >> inode->i_blkbits;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (unlikely(error))
		return error;

	gfs2_trans_add_bh(ip->i_gl, dibh, 1);

	if (gfs2_is_stuffed(ip)) {
		error = gfs2_unstuff_dinode(ip, NULL);
		if (unlikely(error))
			goto out;
	}

	while (len) {
		struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
		bh_map.b_size = len;
		set_buffer_zeronew(&bh_map);

		error = gfs2_block_map(inode, lblock, &bh_map, 1);
		if (unlikely(error))
			goto out;
		len -= bh_map.b_size;
		nr_blks = bh_map.b_size >> inode->i_blkbits;
		lblock += nr_blks;
		if (!buffer_new(&bh_map))
			continue;
		if (unlikely(!buffer_zeronew(&bh_map))) {
			error = -EIO;
			goto out;
		}
	}
	if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
		i_size_write(inode, offset + size);

	mark_inode_dirty(inode);

out:
	brelse(dibh);
	return error;
}

static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
			    unsigned int *data_blocks, unsigned int *ind_blocks)
{
	const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
	unsigned int max_blocks = ip->i_rgd->rd_free_clone;
	unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);

	for (tmp = max_data; tmp > sdp->sd_diptrs;) {
		tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
		max_data -= tmp;
	}
	/* This calculation isn't the exact reverse of gfs2_write_calc_reserve,
	   so it might end up with fewer data blocks */
	if (max_data <= *data_blocks)
		return;
	*data_blocks = max_data;
	*ind_blocks = max_blocks - max_data;
	*len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift;
	if (*len > max) {
		*len = max;
		gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks);
	}
}

static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
			   loff_t len)
{
	struct inode *inode = file_inode(file);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_inode *ip = GFS2_I(inode);
	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
	loff_t bytes, max_bytes;
	struct gfs2_qadata *qa;
	int error;
	const loff_t pos = offset;
	const loff_t count = len;
	loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);
	loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
	loff_t max_chunk_size = UINT_MAX & bsize_mask;
	next = (next + 1) << sdp->sd_sb.sb_bsize_shift;

	/* We only support the FALLOC_FL_KEEP_SIZE mode */
	if (mode & ~FALLOC_FL_KEEP_SIZE)
		return -EOPNOTSUPP;

	offset &= bsize_mask;

	len = next - offset;
	bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;
	if (!bytes)
		bytes = UINT_MAX;
	bytes &= bsize_mask;
	if (bytes == 0)
		bytes = sdp->sd_sb.sb_bsize;

	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
	error = gfs2_glock_nq(&ip->i_gh);
	if (unlikely(error))
		goto out_uninit;

	while (len > 0) {
		if (len < bytes)
			bytes = len;
		if (!gfs2_write_alloc_required(ip, offset, bytes)) {
			len -= bytes;
			offset += bytes;
			continue;
		}
		qa = gfs2_qadata_get(ip);
		if (!qa) {
			error = -ENOMEM;
			goto out_unlock;
		}

		error = gfs2_quota_lock_check(ip);
		if (error)
			goto out_alloc_put;

retry:
		gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);

		error = gfs2_inplace_reserve(ip, data_blocks + ind_blocks);
		if (error) {
			if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
				bytes >>= 1;
				bytes &= bsize_mask;
				if (bytes == 0)
					bytes = sdp->sd_sb.sb_bsize;
				goto retry;
			}
			goto out_qunlock;
		}
		max_bytes = bytes;
		calc_max_reserv(ip, (len > max_chunk_size)? max_chunk_size: len,
				&max_bytes, &data_blocks, &ind_blocks);

		rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
			  RES_RG_HDR + gfs2_rg_blocks(ip);
		if (gfs2_is_jdata(ip))
			rblocks += data_blocks ? data_blocks : 1;

		error = gfs2_trans_begin(sdp, rblocks,
					 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
		if (error)
			goto out_trans_fail;

		error = fallocate_chunk(inode, offset, max_bytes, mode);
		gfs2_trans_end(sdp);

		if (error)
			goto out_trans_fail;

		len -= max_bytes;
		offset += max_bytes;
		gfs2_inplace_release(ip);
		gfs2_quota_unlock(ip);
		gfs2_qadata_put(ip);
	}

	if (error == 0)
		error = generic_write_sync(file, pos, count);
	goto out_unlock;

out_trans_fail:
	gfs2_inplace_release(ip);
out_qunlock:
	gfs2_quota_unlock(ip);
out_alloc_put:
	gfs2_qadata_put(ip);
out_unlock:
	gfs2_glock_dq(&ip->i_gh);
out_uninit:
	gfs2_holder_uninit(&ip->i_gh);
	return error;
}
Ejemplo n.º 16
0
/*
 * NAME:	jfs_mknod
 *
 * FUNCTION:	Create a special file (device)
 */
static int jfs_mknod(struct inode *dir, struct dentry *dentry,
		umode_t 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);
		clear_nlink(ip);
		unlock_new_inode(ip);
		iput(ip);
	} else {
		unlock_new_inode(ip);
		d_instantiate(dentry, ip);
	}

      out1:
	free_UCSname(&dname);

      out:
	jfs_info("jfs_mknod: returning %d", rc);
	return rc;
}
Ejemplo n.º 17
0
static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
			struct inode *new_dir, struct dentry *new_dentry)
{
	struct f2fs_sb_info *sbi = F2FS_SB(old_dir->i_sb);
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
	struct page *old_dir_page;
	struct page *old_page, *new_page;
	struct f2fs_dir_entry *old_dir_entry = NULL;
	struct f2fs_dir_entry *old_entry;
	struct f2fs_dir_entry *new_entry;
	int err = -ENOENT;

	f2fs_balance_fs(sbi);

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

	if (S_ISDIR(old_inode->i_mode)) {
		err = -EIO;
		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
		if (!old_dir_entry)
			goto out_old;
	}

	if (new_inode) {

		err = -ENOTEMPTY;
		if (old_dir_entry && !f2fs_empty_dir(new_inode))
			goto out_dir;

		err = -ENOENT;
		new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
						&new_page);
		if (!new_entry)
			goto out_dir;

		f2fs_lock_op(sbi);

		err = acquire_orphan_inode(sbi);
		if (err)
			goto put_out_dir;

		if (update_dent_inode(old_inode, &new_dentry->d_name)) {
			release_orphan_inode(sbi);
			goto put_out_dir;
		}

		f2fs_set_link(new_dir, new_entry, new_page, old_inode);

		new_inode->i_ctime = CURRENT_TIME;
		down_write(&F2FS_I(new_inode)->i_sem);
		if (old_dir_entry)
			drop_nlink(new_inode);
		drop_nlink(new_inode);
		up_write(&F2FS_I(new_inode)->i_sem);

		mark_inode_dirty(new_inode);

		if (!new_inode->i_nlink)
			add_orphan_inode(sbi, new_inode->i_ino);
		else
			release_orphan_inode(sbi);

		update_inode_page(old_inode);
		update_inode_page(new_inode);
	} else {
		f2fs_lock_op(sbi);

		err = f2fs_add_link(new_dentry, old_inode);
		if (err) {
			f2fs_unlock_op(sbi);
			goto out_dir;
		}

		if (old_dir_entry) {
			inc_nlink(new_dir);
			update_inode_page(new_dir);
		}
	}

	down_write(&F2FS_I(old_inode)->i_sem);
	file_lost_pino(old_inode);
	up_write(&F2FS_I(old_inode)->i_sem);

	old_inode->i_ctime = CURRENT_TIME;
	mark_inode_dirty(old_inode);

	f2fs_delete_entry(old_entry, old_page, NULL);

	if (old_dir_entry) {
		if (old_dir != new_dir) {
			f2fs_set_link(old_inode, old_dir_entry,
						old_dir_page, new_dir);
			update_inode_page(old_inode);
		} else {
			kunmap(old_dir_page);
			f2fs_put_page(old_dir_page, 0);
		}
		drop_nlink(old_dir);
		mark_inode_dirty(old_dir);
		update_inode_page(old_dir);
	}

	f2fs_unlock_op(sbi);
	return 0;

put_out_dir:
	f2fs_unlock_op(sbi);
	kunmap(new_page);
	f2fs_put_page(new_page, 0);
out_dir:
	if (old_dir_entry) {
		kunmap(old_dir_page);
		f2fs_put_page(old_dir_page, 0);
	}
out_old:
	kunmap(old_page);
	f2fs_put_page(old_page, 0);
out:
	return err;
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
static int f2fs_cross_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 f2fs_sb_info *sbi = F2FS_SB(sb);
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
	struct page *old_dir_page, *new_dir_page;
	struct page *old_page, *new_page;
	struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL;
	struct f2fs_dir_entry *old_entry, *new_entry;
	int old_nlink = 0, new_nlink = 0;
	int err = -ENOENT;

	f2fs_balance_fs(sbi);

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

	new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page);
	if (!new_entry)
		goto out_old;

	/* prepare for updating ".." directory entry info later */
	if (old_dir != new_dir) {
		if (S_ISDIR(old_inode->i_mode)) {
			err = -EIO;
			old_dir_entry = f2fs_parent_dir(old_inode,
							&old_dir_page);
			if (!old_dir_entry)
				goto out_new;
		}

		if (S_ISDIR(new_inode->i_mode)) {
			err = -EIO;
			new_dir_entry = f2fs_parent_dir(new_inode,
							&new_dir_page);
			if (!new_dir_entry)
				goto out_old_dir;
		}
	}

	/*
	 * If cross rename between file and directory those are not
	 * in the same directory, we will inc nlink of file's parent
	 * later, so we should check upper boundary of its nlink.
	 */
	if ((!old_dir_entry || !new_dir_entry) &&
				old_dir_entry != new_dir_entry) {
		old_nlink = old_dir_entry ? -1 : 1;
		new_nlink = -old_nlink;
		err = -EMLINK;
		if ((old_nlink > 0 && old_inode->i_nlink >= F2FS_LINK_MAX) ||
			(new_nlink > 0 && new_inode->i_nlink >= F2FS_LINK_MAX))
			goto out_new_dir;
	}

	f2fs_lock_op(sbi);

	err = update_dent_inode(old_inode, &new_dentry->d_name);
	if (err)
		goto out_unlock;

	err = update_dent_inode(new_inode, &old_dentry->d_name);
	if (err)
		goto out_undo;

	/* update ".." directory entry info of old dentry */
	if (old_dir_entry)
		f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);

	/* update ".." directory entry info of new dentry */
	if (new_dir_entry)
		f2fs_set_link(new_inode, new_dir_entry, new_dir_page, old_dir);

	/* update directory entry info of old dir inode */
	f2fs_set_link(old_dir, old_entry, old_page, new_inode);

	down_write(&F2FS_I(old_inode)->i_sem);
	file_lost_pino(old_inode);
	up_write(&F2FS_I(old_inode)->i_sem);

	update_inode_page(old_inode);

	old_dir->i_ctime = CURRENT_TIME;
	if (old_nlink) {
		down_write(&F2FS_I(old_dir)->i_sem);
		if (old_nlink < 0)
			drop_nlink(old_dir);
		else
			inc_nlink(old_dir);
		up_write(&F2FS_I(old_dir)->i_sem);
	}
	mark_inode_dirty(old_dir);
	update_inode_page(old_dir);

	/* update directory entry info of new dir inode */
	f2fs_set_link(new_dir, new_entry, new_page, old_inode);

	down_write(&F2FS_I(new_inode)->i_sem);
	file_lost_pino(new_inode);
	up_write(&F2FS_I(new_inode)->i_sem);

	update_inode_page(new_inode);

	new_dir->i_ctime = CURRENT_TIME;
	if (new_nlink) {
		down_write(&F2FS_I(new_dir)->i_sem);
		if (new_nlink < 0)
			drop_nlink(new_dir);
		else
			inc_nlink(new_dir);
		up_write(&F2FS_I(new_dir)->i_sem);
	}
	mark_inode_dirty(new_dir);
	update_inode_page(new_dir);

	f2fs_unlock_op(sbi);
	return 0;
out_undo:
	/* Still we may fail to recover name info of f2fs_inode here */
	update_dent_inode(old_inode, &old_dentry->d_name);
out_unlock:
	f2fs_unlock_op(sbi);
out_new_dir:
	if (new_dir_entry) {
		kunmap(new_dir_page);
		f2fs_put_page(new_dir_page, 0);
	}
out_old_dir:
	if (old_dir_entry) {
		kunmap(old_dir_page);
		f2fs_put_page(old_dir_page, 0);
	}
out_new:
	kunmap(new_page);
	f2fs_put_page(new_page, 0);
out_old:
	kunmap(old_page);
	f2fs_put_page(old_page, 0);
out:
	return err;
}
Ejemplo n.º 20
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);

	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) {
		drop_nlink(ip); /* 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;
}
Ejemplo n.º 21
0
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) {
			/* "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 = 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);	/* 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) {
		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 {
		/*
		 * 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;
}
Ejemplo n.º 22
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:
	clear_nlink(inode);
	mark_inode_dirty(inode);
	iput(inode);
	return error;
}
Ejemplo n.º 23
0
static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
{
    struct super_block * sb;
    struct ufs_sb_private_info * uspi;
    struct ufs_buffer_head * ind_ubh;
    __fs32 * ind;
    unsigned indirect_block, i, tmp;
    unsigned frag_to_free, free_count;
    int retry;

    UFSD("ENTER\n");

    sb = inode->i_sb;
    uspi = UFS_SB(sb)->s_uspi;

    frag_to_free = 0;
    free_count = 0;
    retry = 0;

    tmp = fs32_to_cpu(sb, *p);
    if (!tmp)
        return 0;
    ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize);
    if (tmp != fs32_to_cpu(sb, *p)) {
        ubh_brelse (ind_ubh);
        return 1;
    }
    if (!ind_ubh) {
        *p = 0;
        return 0;
    }

    indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0;
    for (i = indirect_block; i < uspi->s_apb; i++) {
        ind = ubh_get_addr32 (ind_ubh, i);
        tmp = fs32_to_cpu(sb, *ind);
        if (!tmp)
            continue;

        *ind = 0;
        ubh_mark_buffer_dirty(ind_ubh);
        if (free_count == 0) {
            frag_to_free = tmp;
            free_count = uspi->s_fpb;
        } else if (free_count > 0 && frag_to_free == tmp - free_count)
            free_count += uspi->s_fpb;
        else {
            ufs_free_blocks (inode, frag_to_free, free_count);
            frag_to_free = tmp;
            free_count = uspi->s_fpb;
        }

        mark_inode_dirty(inode);
    }

    if (free_count > 0) {
        ufs_free_blocks (inode, frag_to_free, free_count);
    }
    for (i = 0; i < uspi->s_apb; i++)
        if (*ubh_get_addr32(ind_ubh,i))
            break;
    if (i >= uspi->s_apb) {
        tmp = fs32_to_cpu(sb, *p);
        *p = 0;

        ufs_free_blocks (inode, tmp, uspi->s_fpb);
        mark_inode_dirty(inode);
        ubh_bforget(ind_ubh);
        ind_ubh = NULL;
    }
    if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
        ubh_ll_rw_block(SWRITE, ind_ubh);
        ubh_wait_on_buffer (ind_ubh);
    }
    ubh_brelse (ind_ubh);

    UFSD("EXIT\n");

    return retry;
}
Ejemplo n.º 24
0
static int expand_inode_data(struct inode *inode, loff_t offset,
					loff_t len, int mode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	pgoff_t index, pg_start, pg_end;
	loff_t new_size = i_size_read(inode);
	loff_t off_start, off_end;
	int ret = 0;

	f2fs_balance_fs(sbi);

	ret = inode_newsize_ok(inode, (len + offset));
	if (ret)
		return ret;

	if (f2fs_has_inline_data(inode)) {
		ret = f2fs_convert_inline_inode(inode);
		if (ret)
			return ret;
	}

	pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
	pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;

	off_start = offset & (PAGE_CACHE_SIZE - 1);
	off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);

	f2fs_lock_op(sbi);

	for (index = pg_start; index <= pg_end; index++) {
		struct dnode_of_data dn;

		if (index == pg_end && !off_end)
			goto noalloc;

		set_new_dnode(&dn, inode, NULL, NULL, 0);
		ret = f2fs_reserve_block(&dn, index);
		if (ret)
			break;
noalloc:
		if (pg_start == pg_end)
			new_size = offset + len;
		else if (index == pg_start && off_start)
			new_size = (loff_t)(index + 1) << PAGE_CACHE_SHIFT;
		else if (index == pg_end)
			new_size = ((loff_t)index << PAGE_CACHE_SHIFT) +
								off_end;
		else
			new_size += PAGE_CACHE_SIZE;
	}

	if (!(mode & FALLOC_FL_KEEP_SIZE) &&
		i_size_read(inode) < new_size) {
		i_size_write(inode, new_size);
		mark_inode_dirty(inode);
		update_inode_page(inode);
	}
	f2fs_unlock_op(sbi);

	return ret;
}
Ejemplo n.º 25
0
static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
{
    struct super_block * sb;
    struct ufs_sb_private_info * uspi;
    struct ufs_buffer_head * dind_bh;
    unsigned i, tmp, dindirect_block;
    __fs32 * dind;
    int retry = 0;

    UFSD("ENTER\n");

    sb = inode->i_sb;
    uspi = UFS_SB(sb)->s_uspi;

    dindirect_block = (DIRECT_BLOCK > offset)
                      ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0;
    retry = 0;

    tmp = fs32_to_cpu(sb, *p);
    if (!tmp)
        return 0;
    dind_bh = ubh_bread(sb, tmp, uspi->s_bsize);
    if (tmp != fs32_to_cpu(sb, *p)) {
        ubh_brelse (dind_bh);
        return 1;
    }
    if (!dind_bh) {
        *p = 0;
        return 0;
    }

    for (i = dindirect_block ; i < uspi->s_apb ; i++) {
        dind = ubh_get_addr32 (dind_bh, i);
        tmp = fs32_to_cpu(sb, *dind);
        if (!tmp)
            continue;
        retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind);
        ubh_mark_buffer_dirty(dind_bh);
    }

    for (i = 0; i < uspi->s_apb; i++)
        if (*ubh_get_addr32 (dind_bh, i))
            break;
    if (i >= uspi->s_apb) {
        tmp = fs32_to_cpu(sb, *p);
        *p = 0;

        ufs_free_blocks(inode, tmp, uspi->s_fpb);
        mark_inode_dirty(inode);
        ubh_bforget(dind_bh);
        dind_bh = NULL;
    }
    if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
        ubh_ll_rw_block(SWRITE, dind_bh);
        ubh_wait_on_buffer (dind_bh);
    }
    ubh_brelse (dind_bh);

    UFSD("EXIT\n");

    return retry;
}
Ejemplo n.º 26
0
int
affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
	       struct dentry *dentry, int type)
{
	struct buffer_head	*dir_bh;
	struct buffer_head	*inode_bh;
	struct buffer_head	*link_bh;
	int			 retval;
	const unsigned char	*name = dentry->d_name.name;
	int			 len  = dentry->d_name.len;

	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino,
		 len,name,type);

	if ((retval = affs_check_name(name,len)))
		return retval;
	if (len > 30)
		len = 30;

	dir_bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
	inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
	link_bh  = NULL;
	retval   = -EIO;
	if (!dir_bh || !inode_bh)
		goto addentry_done;
	if (link) {
		link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
		if (!link_bh)
			goto addentry_done;
	}
	((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT);
	((struct dir_front *)inode_bh->b_data)->own_key      = cpu_to_be32(inode->i_ino);
	DIR_END(inode_bh->b_data,inode)->dir_name[0]         = len;
	strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
	DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type);
	DIR_END(inode_bh->b_data,inode)->parent         = cpu_to_be32(dir->i_ino);

	lock_super(inode->i_sb);
	retval = affs_insert_hash(dir->i_ino,inode_bh,dir);

	if (link_bh) {
		LINK_END(inode_bh->b_data,inode)->original   = cpu_to_be32(link->i_ino);
		LINK_END(inode_bh->b_data,inode)->link_chain =
						FILE_END(link_bh->b_data,link)->link_chain;
		FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
		link->i_version = ++event;
		mark_inode_dirty(link);
		mark_buffer_dirty(link_bh,1);
	}
	affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
	affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
	dir->i_version = ++event;
	dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
	unlock_super(inode->i_sb);

	mark_inode_dirty(dir);
	mark_inode_dirty(inode);
	mark_buffer_dirty(dir_bh,1);
	mark_buffer_dirty(inode_bh,1);

addentry_done:
	affs_brelse(dir_bh);
	affs_brelse(inode_bh);
	affs_brelse(link_bh);

	return retval;
}
Ejemplo n.º 27
0
static int ufs_trunc_direct (struct inode * inode)
{
    struct ufs_inode_info *ufsi = UFS_I(inode);
    struct super_block * sb;
    struct ufs_sb_private_info * uspi;
    __fs32 * p;
    unsigned frag1, frag2, frag3, frag4, block1, block2;
    unsigned frag_to_free, free_count;
    unsigned i, tmp;
    int retry;

    UFSD("ENTER\n");

    sb = inode->i_sb;
    uspi = UFS_SB(sb)->s_uspi;

    frag_to_free = 0;
    free_count = 0;
    retry = 0;

    frag1 = DIRECT_FRAGMENT;
    frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
    frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
    frag3 = frag4 & ~uspi->s_fpbmask;
    block1 = block2 = 0;
    if (frag2 > frag3) {
        frag2 = frag4;
        frag3 = frag4 = 0;
    }
    else if (frag2 < frag3) {
        block1 = ufs_fragstoblks (frag2);
        block2 = ufs_fragstoblks (frag3);
    }

    UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4);

    if (frag1 >= frag2)
        goto next1;

    /*
     * Free first free fragments
     */
    p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1);
    tmp = fs32_to_cpu(sb, *p);
    if (!tmp )
        ufs_panic (sb, "ufs_trunc_direct", "internal error");
    frag1 = ufs_fragnum (frag1);
    frag2 = ufs_fragnum (frag2);

    ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
    mark_inode_dirty(inode);
    frag_to_free = tmp + frag1;

next1:
    /*
     * Free whole blocks
     */
    for (i = block1 ; i < block2; i++) {
        p = ufsi->i_u1.i_data + i;
        tmp = fs32_to_cpu(sb, *p);
        if (!tmp)
            continue;

        *p = 0;

        if (free_count == 0) {
            frag_to_free = tmp;
            free_count = uspi->s_fpb;
        } else if (free_count > 0 && frag_to_free == tmp - free_count)
            free_count += uspi->s_fpb;
        else {
            ufs_free_blocks (inode, frag_to_free, free_count);
            frag_to_free = tmp;
            free_count = uspi->s_fpb;
        }
        mark_inode_dirty(inode);
    }

    if (free_count > 0)
        ufs_free_blocks (inode, frag_to_free, free_count);

    if (frag3 >= frag4)
        goto next3;

    /*
     * Free last free fragments
     */
    p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3);
    tmp = fs32_to_cpu(sb, *p);
    if (!tmp )
        ufs_panic(sb, "ufs_truncate_direct", "internal error");
    frag4 = ufs_fragnum (frag4);

    *p = 0;

    ufs_free_fragments (inode, tmp, frag4);
    mark_inode_dirty(inode);
next3:

    UFSD("EXIT\n");
    return retry;
}
Ejemplo n.º 28
0
Archivo: ialloc.c Proyecto: 274914765/C
struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
{
    struct super_block *sb = dir->i_sb;
    struct udf_sb_info *sbi = UDF_SB(sb);
    struct inode *inode;
    int block;
    uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
    struct udf_inode_info *iinfo;
    struct udf_inode_info *dinfo = UDF_I(dir);

    inode = new_inode(sb);

    if (!inode) {
        *err = -ENOMEM;
        return NULL;
    }
    *err = -ENOSPC;

    iinfo = UDF_I(inode);
    iinfo->i_unique = 0;
    iinfo->i_lenExtents = 0;
    iinfo->i_next_alloc_block = 0;
    iinfo->i_next_alloc_goal = 0;
    iinfo->i_strat4096 = 0;

    block = udf_new_block(dir->i_sb, NULL,
                  dinfo->i_location.partitionReferenceNum,
                  start, err);
    if (*err) {
        iput(inode);
        return NULL;
    }

    mutex_lock(&sbi->s_alloc_mutex);
    if (sbi->s_lvid_bh) {
        struct logicalVolIntegrityDesc *lvid =
            (struct logicalVolIntegrityDesc *)
            sbi->s_lvid_bh->b_data;
        struct logicalVolIntegrityDescImpUse *lvidiu =
                            udf_sb_lvidiu(sbi);
        struct logicalVolHeaderDesc *lvhd;
        uint64_t uniqueID;
        lvhd = (struct logicalVolHeaderDesc *)
                (lvid->logicalVolContentsUse);
        if (S_ISDIR(mode))
            le32_add_cpu(&lvidiu->numDirs, 1);
        else
            le32_add_cpu(&lvidiu->numFiles, 1);
        iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID);
        if (!(++uniqueID & 0x00000000FFFFFFFFUL))
            uniqueID += 16;
        lvhd->uniqueID = cpu_to_le64(uniqueID);
        mark_buffer_dirty(sbi->s_lvid_bh);
    }
    inode->i_mode = mode;
    inode->i_uid = current->fsuid;
    if (dir->i_mode & S_ISGID) {
        inode->i_gid = dir->i_gid;
        if (S_ISDIR(mode))
            mode |= S_ISGID;
    } else {
        inode->i_gid = current->fsgid;
    }

    iinfo->i_location.logicalBlockNum = block;
    iinfo->i_location.partitionReferenceNum =
                dinfo->i_location.partitionReferenceNum;
    inode->i_ino = udf_get_lb_pblock(sb, iinfo->i_location, 0);
    inode->i_blocks = 0;
    iinfo->i_lenEAttr = 0;
    iinfo->i_lenAlloc = 0;
    iinfo->i_use = 0;
    if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
        iinfo->i_efe = 1;
        if (UDF_VERS_USE_EXTENDED_FE > sbi->s_udfrev)
            sbi->s_udfrev = UDF_VERS_USE_EXTENDED_FE;
        iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
                        sizeof(struct extendedFileEntry),
                        GFP_KERNEL);
    } else {
        iinfo->i_efe = 0;
        iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
                        sizeof(struct fileEntry),
                        GFP_KERNEL);
    }
    if (!iinfo->i_ext.i_data) {
        iput(inode);
        *err = -ENOMEM;
        mutex_unlock(&sbi->s_alloc_mutex);
        return NULL;
    }
    if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
        iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
    else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
        iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
    else
        iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
    inode->i_mtime = inode->i_atime = inode->i_ctime =
        iinfo->i_crtime = current_fs_time(inode->i_sb);
    insert_inode_hash(inode);
    mark_inode_dirty(inode);
    mutex_unlock(&sbi->s_alloc_mutex);

    if (DQUOT_ALLOC_INODE(inode)) {
        DQUOT_DROP(inode);
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
        iput(inode);
        *err = -EDQUOT;
        return NULL;
    }

    *err = 0;
    return inode;
}
Ejemplo n.º 29
0
int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
					const void *value, size_t value_len)
{
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
	struct f2fs_inode_info *fi = F2FS_I(inode);
	struct f2fs_xattr_header *header = NULL;
	struct f2fs_xattr_entry *here, *last;
	struct page *page;
	void *base_addr;
	int error, found, free, name_len, newsize;
	char *pval;

	if (name == NULL)
		return -EINVAL;
	name_len = strlen(name);

	if (value == NULL)
		value_len = 0;

	if (name_len > 255 || value_len > MAX_VALUE_LEN)
		return -ERANGE;

	mutex_lock_op(sbi, NODE_NEW);
	if (!fi->i_xattr_nid) {
		/* Allocate new attribute block */
		struct dnode_of_data dn;

		if (!alloc_nid(sbi, &fi->i_xattr_nid)) {
			mutex_unlock_op(sbi, NODE_NEW);
			return -ENOSPC;
		}
		set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid);
		mark_inode_dirty(inode);

		page = new_node_page(&dn, XATTR_NODE_OFFSET);
		if (IS_ERR(page)) {
			alloc_nid_failed(sbi, fi->i_xattr_nid);
			fi->i_xattr_nid = 0;
			mutex_unlock_op(sbi, NODE_NEW);
			return PTR_ERR(page);
		}

		alloc_nid_done(sbi, fi->i_xattr_nid);
		base_addr = page_address(page);
		header = XATTR_HDR(base_addr);
		header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
		header->h_refcount = cpu_to_le32(1);
	} else {
		/* The inode already has an extended attribute block. */
		page = get_node_page(sbi, fi->i_xattr_nid);
		if (IS_ERR(page)) {
			mutex_unlock_op(sbi, NODE_NEW);
			return PTR_ERR(page);
		}

		base_addr = page_address(page);
		header = XATTR_HDR(base_addr);
	}

	if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
		error = -EIO;
		goto cleanup;
	}

	/* find entry with wanted name. */
	found = 0;
	list_for_each_xattr(here, base_addr) {
		if (here->e_name_index != name_index)
			continue;
		if (here->e_name_len != name_len)
			continue;
		if (!memcmp(here->e_name, name, name_len)) {
			found = 1;
			break;
		}
	}

	last = here;

	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) +
			name_len + value_len);

	/* 1. Check space */
	if (value) {
		/* If value is NULL, it is remove operation.
		 * In case of update operation, we caculate free.
		 */
		free = MIN_OFFSET - ((char *)last - (char *)header);
		if (found)
			free = free - ENTRY_SIZE(here);

		if (free < newsize) {
			error = -ENOSPC;
			goto cleanup;
		}
	}

	/* 2. Remove old entry */
	if (found) {
		/* If entry is found, remove old entry.
		 * If not found, remove operation is not needed.
		 */
		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
		int oldsize = ENTRY_SIZE(here);

		memmove(here, next, (char *)last - (char *)next);
		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
		memset(last, 0, oldsize);
	}

	/* 3. Write new entry */
	if (value) {
		/* Before we come here, old entry is removed.
		 * We just write new entry. */
		memset(last, 0, newsize);
		last->e_name_index = name_index;
		last->e_name_len = name_len;
		memcpy(last->e_name, name, name_len);
		pval = last->e_name + name_len;
		memcpy(pval, value, value_len);
		last->e_value_size = cpu_to_le16(value_len);
	}

	set_page_dirty(page);
	f2fs_put_page(page, 1);

	if (is_inode_flag_set(fi, FI_ACL_MODE)) {
		inode->i_mode = fi->i_acl_mode;
		inode->i_ctime = CURRENT_TIME_SEC;
		clear_inode_flag(fi, FI_ACL_MODE);
	}
	f2fs_write_inode(inode, NULL);
	mutex_unlock_op(sbi, NODE_NEW);

	return 0;
cleanup:
	f2fs_put_page(page, 1);
	mutex_unlock_op(sbi, NODE_NEW);
	return error;
}