diff options
Diffstat (limited to 'fs/gfs2/ops_inode.c')
| -rw-r--r-- | fs/gfs2/ops_inode.c | 1612 | 
1 files changed, 0 insertions, 1612 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c deleted file mode 100644 index 12cbea7502c..00000000000 --- a/fs/gfs2/ops_inode.c +++ /dev/null @@ -1,1612 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/completion.h> -#include <linux/buffer_head.h> -#include <linux/namei.h> -#include <linux/mm.h> -#include <linux/xattr.h> -#include <linux/posix_acl.h> -#include <linux/gfs2_ondisk.h> -#include <linux/crc32.h> -#include <linux/fiemap.h> -#include <linux/swap.h> -#include <linux/falloc.h> -#include <asm/uaccess.h> - -#include "gfs2.h" -#include "incore.h" -#include "acl.h" -#include "bmap.h" -#include "dir.h" -#include "xattr.h" -#include "glock.h" -#include "inode.h" -#include "meta_io.h" -#include "quota.h" -#include "rgrp.h" -#include "trans.h" -#include "util.h" -#include "super.h" - -/** - * 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 gfs2_inode *dip = GFS2_I(dir); -	struct gfs2_sbd *sdp = GFS2_SB(dir); -	struct gfs2_holder ghs[2]; -	struct inode *inode; - -	gfs2_holder_init(dip->i_gl, 0, 0, ghs); - -	for (;;) { -		inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); -		if (!IS_ERR(inode)) { -			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); -			break; -		} else if (PTR_ERR(inode) != -EEXIST || -			   (nd && nd->flags & LOOKUP_EXCL)) { -			gfs2_holder_uninit(ghs); -			return PTR_ERR(inode); -		} - -		inode = gfs2_lookupi(dir, &dentry->d_name, 0); -		if (inode) { -			if (!IS_ERR(inode)) { -				gfs2_holder_uninit(ghs); -				break; -			} else { -				gfs2_holder_uninit(ghs); -				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; - -	dentry->d_op = &gfs2_dops; - -	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]; -	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); -	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; -} - -/* - * 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); -	if (error) -		return error; - -	error = gfs2_dir_check(&dip->i_inode, name, ip); -	if (error) -		return error; - -	return 0; -} - -/** - * gfs2_unlink - Unlink a file - * @dir: The inode of the directory containing the file to unlink - * @dentry: The file itself - * - * Unlink a file.  Call gfs2_unlinki() - * - * Returns: errno - */ - -static int gfs2_unlink(struct inode *dir, struct dentry *dentry) -{ -	struct gfs2_inode *dip = GFS2_I(dir); -	struct gfs2_sbd *sdp = GFS2_SB(dir); -	struct gfs2_inode *ip = GFS2_I(dentry->d_inode); -	struct gfs2_holder ghs[3]; -	struct gfs2_rgrpd *rgd; -	struct gfs2_holder ri_gh; -	int error; - -	error = gfs2_rindex_hold(sdp, &ri_gh); -	if (error) -		return error; - -	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); -	gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1); - -	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); -	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - - -	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_glock_nq(ghs + 2); /* rgrp */ -	if (error) -		goto out_rgrp; - -	error = gfs2_unlink_ok(dip, &dentry->d_name, ip); -	if (error) -		goto out_gunlock; - -	error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); -	if (error) -		goto out_gunlock; - -	error = gfs2_dir_del(dip, &dentry->d_name); -        if (error) -                goto out_end_trans; - -	error = gfs2_change_nlink(ip, -1); - -out_end_trans: -	gfs2_trans_end(sdp); -out_gunlock: -	gfs2_glock_dq(ghs + 2); -out_rgrp: -	gfs2_holder_uninit(ghs + 2); -	gfs2_glock_dq(ghs + 1); -out_child: -	gfs2_holder_uninit(ghs + 1); -	gfs2_glock_dq(ghs); -out_parent: -	gfs2_holder_uninit(ghs); -	gfs2_glock_dq_uninit(&ri_gh); -	return error; -} - -/** - * gfs2_symlink - Create a symlink - * @dir: The directory to create the symlink in - * @dentry: The dentry to put the symlink in - * @symname: The thing which the link points to - * - * Returns: errno - */ - -static int gfs2_symlink(struct inode *dir, struct dentry *dentry, -			const char *symname) -{ -	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 size; -	int error; - -	/* Must be stuffed with a null terminator for gfs2_follow_link() */ -	size = strlen(symname); -	if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) -		return -ENAMETOOLONG; - -	gfs2_holder_init(dip->i_gl, 0, 0, ghs); - -	inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0); -	if (IS_ERR(inode)) { -		gfs2_holder_uninit(ghs); -		return PTR_ERR(inode); -	} - -	ip = ghs[1].gh_gl->gl_object; - -	i_size_write(inode, size); - -	error = gfs2_meta_inode_buffer(ip, &dibh); - -	if (!gfs2_assert_withdraw(sdp, !error)) { -		gfs2_dinode_out(ip, dibh->b_data); -		memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, -		       size); -		brelse(dibh); -	} - -	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; -} - -/** - * gfs2_mkdir - Make a directory - * @dir: The parent directory of the new one - * @dentry: The dentry of the new directory - * @mode: The mode of the new directory - * - * Returns: errno - */ - -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; -} - -/** - * gfs2_rmdiri - Remove a directory - * @dip: The parent directory of the directory to be removed - * @name: The name of the directory to be removed - * @ip: The GFS2 inode of the directory to be removed - * - * Assumes Glocks on dip and ip are held - * - * Returns: errno - */ - -static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, -		       struct gfs2_inode *ip) -{ -	int error; - -	if (ip->i_entries != 2) { -		if (gfs2_consist_inode(ip)) -			gfs2_dinode_print(ip); -		return -EIO; -	} - -	error = gfs2_dir_del(dip, name); -	if (error) -		return error; - -	error = gfs2_change_nlink(dip, -1); -	if (error) -		return error; - -	error = gfs2_dir_del(ip, &gfs2_qdot); -	if (error) -		return error; - -	error = gfs2_dir_del(ip, &gfs2_qdotdot); -	if (error) -		return error; - -	/* It looks odd, but it really should be done twice */ -	error = gfs2_change_nlink(ip, -1); -	if (error) -		return error; - -	error = gfs2_change_nlink(ip, -1); -	if (error) -		return error; - -	return error; -} - -/** - * gfs2_rmdir - Remove a directory - * @dir: The parent directory of the directory to be removed - * @dentry: The dentry of the directory to remove - * - * Remove a directory. Call gfs2_rmdiri() - * - * Returns: errno - */ - -static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) -{ -	struct gfs2_inode *dip = GFS2_I(dir); -	struct gfs2_sbd *sdp = GFS2_SB(dir); -	struct gfs2_inode *ip = GFS2_I(dentry->d_inode); -	struct gfs2_holder ghs[3]; -	struct gfs2_rgrpd *rgd; -	struct gfs2_holder ri_gh; -	int error; - -	error = gfs2_rindex_hold(sdp, &ri_gh); -	if (error) -		return error; -	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); -	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - -	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); -	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - -	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_glock_nq(ghs + 2); /* rgrp */ -	if (error) -		goto out_rgrp; - -	error = gfs2_unlink_ok(dip, &dentry->d_name, ip); -	if (error) -		goto out_gunlock; - -	if (ip->i_entries < 2) { -		if (gfs2_consist_inode(ip)) -			gfs2_dinode_print(ip); -		error = -EIO; -		goto out_gunlock; -	} -	if (ip->i_entries > 2) { -		error = -ENOTEMPTY; -		goto out_gunlock; -	} - -	error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0); -	if (error) -		goto out_gunlock; - -	error = gfs2_rmdiri(dip, &dentry->d_name, ip); - -	gfs2_trans_end(sdp); - -out_gunlock: -	gfs2_glock_dq(ghs + 2); -out_rgrp: -	gfs2_holder_uninit(ghs + 2); -	gfs2_glock_dq(ghs + 1); -out_child: -	gfs2_holder_uninit(ghs + 1); -	gfs2_glock_dq(ghs); -out_parent: -	gfs2_holder_uninit(ghs); -	gfs2_glock_dq_uninit(&ri_gh); -	return error; -} - -/** - * gfs2_mknod - Make a special file - * @dir: The directory in which the special file will reside - * @dentry: The dentry of the special file - * @mode: The mode of the special file - * @rdev: The device specification of the special file - * - */ - -static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, -		      dev_t dev) -{ -	struct gfs2_inode *dip = GFS2_I(dir); -	struct gfs2_sbd *sdp = GFS2_SB(dir); -	struct gfs2_holder ghs[2]; -	struct inode *inode; - -	gfs2_holder_init(dip->i_gl, 0, 0, ghs); - -	inode = gfs2_createi(ghs, &dentry->d_name, mode, dev); -	if (IS_ERR(inode)) { -		gfs2_holder_uninit(ghs); -		return PTR_ERR(inode); -	} - -	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; -} - -/* - * gfs2_ok_to_move - check if it's ok to move a directory to another directory - * @this: move this - * @to: to here - * - * Follow @to back to the root and make sure we don't encounter @this - * Assumes we already hold the rename lock. - * - * Returns: errno - */ - -static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) -{ -	struct inode *dir = &to->i_inode; -	struct super_block *sb = dir->i_sb; -	struct inode *tmp; -	int error = 0; - -	igrab(dir); - -	for (;;) { -		if (dir == &this->i_inode) { -			error = -EINVAL; -			break; -		} -		if (dir == sb->s_root->d_inode) { -			error = 0; -			break; -		} - -		tmp = gfs2_lookupi(dir, &gfs2_qdotdot, 1); -		if (IS_ERR(tmp)) { -			error = PTR_ERR(tmp); -			break; -		} - -		iput(dir); -		dir = tmp; -	} - -	iput(dir); - -	return error; -} - -/** - * gfs2_rename - Rename a file - * @odir: Parent directory of old file name - * @odentry: The old dentry of the file - * @ndir: Parent directory of new file name - * @ndentry: The new dentry of the file - * - * Returns: errno - */ - -static int gfs2_rename(struct inode *odir, struct dentry *odentry, -		       struct inode *ndir, struct dentry *ndentry) -{ -	struct gfs2_inode *odip = GFS2_I(odir); -	struct gfs2_inode *ndip = GFS2_I(ndir); -	struct gfs2_inode *ip = GFS2_I(odentry->d_inode); -	struct gfs2_inode *nip = NULL; -	struct gfs2_sbd *sdp = GFS2_SB(odir); -	struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh; -	struct gfs2_rgrpd *nrgd; -	unsigned int num_gh; -	int dir_rename = 0; -	int alloc_required = 0; -	unsigned int x; -	int error; - -	if (ndentry->d_inode) { -		nip = GFS2_I(ndentry->d_inode); -		if (ip == nip) -			return 0; -	} - -	error = gfs2_rindex_hold(sdp, &ri_gh); -	if (error) -		return error; - -	if (odip != ndip) { -		error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, -					   0, &r_gh); -		if (error) -			goto out; - -		if (S_ISDIR(ip->i_inode.i_mode)) { -			dir_rename = 1; -			/* don't move a dirctory into it's subdir */ -			error = gfs2_ok_to_move(ip, ndip); -			if (error) -				goto out_gunlock_r; -		} -	} - -	num_gh = 1; -	gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); -	if (odip != ndip) { -		gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); -		num_gh++; -	} -	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); -	num_gh++; - -	if (nip) { -		gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); -		num_gh++; -		/* grab the resource lock for unlink flag twiddling  -		 * this is the case of the target file already existing -		 * so we unlink before doing the rename -		 */ -		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr); -		if (nrgd) -			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); -	} - -	for (x = 0; x < num_gh; x++) { -		error = gfs2_glock_nq(ghs + x); -		if (error) -			goto out_gunlock; -	} - -	/* Check out the old directory */ - -	error = gfs2_unlink_ok(odip, &odentry->d_name, ip); -	if (error) -		goto out_gunlock; - -	/* Check out the new directory */ - -	if (nip) { -		error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); -		if (error) -			goto out_gunlock; - -		if (S_ISDIR(nip->i_inode.i_mode)) { -			if (nip->i_entries < 2) { -				if (gfs2_consist_inode(nip)) -					gfs2_dinode_print(nip); -				error = -EIO; -				goto out_gunlock; -			} -			if (nip->i_entries > 2) { -				error = -ENOTEMPTY; -				goto out_gunlock; -			} -		} -	} else { -		error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC); -		if (error) -			goto out_gunlock; - -		error = gfs2_dir_check(ndir, &ndentry->d_name, NULL); -		switch (error) { -		case -ENOENT: -			error = 0; -			break; -		case 0: -			error = -EEXIST; -		default: -			goto out_gunlock; -		}; - -		if (odip != ndip) { -			if (!ndip->i_inode.i_nlink) { -				error = -EINVAL; -				goto out_gunlock; -			} -			if (ndip->i_entries == (u32)-1) { -				error = -EFBIG; -				goto out_gunlock; -			} -			if (S_ISDIR(ip->i_inode.i_mode) && -			    ndip->i_inode.i_nlink == (u32)-1) { -				error = -EMLINK; -				goto out_gunlock; -			} -		} -	} - -	/* Check out the dir to be renamed */ - -	if (dir_rename) { -		error = gfs2_permission(odentry->d_inode, MAY_WRITE); -		if (error) -			goto out_gunlock; -	} - -	if (nip == NULL) -		alloc_required = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); -	error = alloc_required; -	if (error < 0) -		goto out_gunlock; -	error = 0; - -	if (alloc_required) { -		struct gfs2_alloc *al = gfs2_alloc_get(ndip); -		if (!al) { -			error = -ENOMEM; -			goto out_gunlock; -		} - -		error = gfs2_quota_lock_check(ndip); -		if (error) -			goto out_alloc; - -		al->al_requested = sdp->sd_max_dirres; - -		error = gfs2_inplace_reserve_ri(ndip); -		if (error) -			goto out_gunlock_q; - -		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + -					 gfs2_rg_blocks(al) + -					 4 * RES_DINODE + 4 * RES_LEAF + -					 RES_STATFS + RES_QUOTA + 4, 0); -		if (error) -			goto out_ipreserv; -	} else { -		error = gfs2_trans_begin(sdp, 4 * RES_DINODE + -					 5 * RES_LEAF + 4, 0); -		if (error) -			goto out_gunlock; -	} - -	/* Remove the target file, if it exists */ - -	if (nip) { -		if (S_ISDIR(nip->i_inode.i_mode)) -			error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); -		else { -			error = gfs2_dir_del(ndip, &ndentry->d_name); -			if (error) -				goto out_end_trans; -			error = gfs2_change_nlink(nip, -1); -		} -		if (error) -			goto out_end_trans; -	} - -	if (dir_rename) { -		error = gfs2_change_nlink(ndip, +1); -		if (error) -			goto out_end_trans; -		error = gfs2_change_nlink(odip, -1); -		if (error) -			goto out_end_trans; - -		error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); -		if (error) -			goto out_end_trans; -	} else { -		struct buffer_head *dibh; -		error = gfs2_meta_inode_buffer(ip, &dibh); -		if (error) -			goto out_end_trans; -		ip->i_inode.i_ctime = CURRENT_TIME; -		gfs2_trans_add_bh(ip->i_gl, dibh, 1); -		gfs2_dinode_out(ip, dibh->b_data); -		brelse(dibh); -	} - -	error = gfs2_dir_del(odip, &odentry->d_name); -	if (error) -		goto out_end_trans; - -	error = gfs2_dir_add(ndir, &ndentry->d_name, ip, IF2DT(ip->i_inode.i_mode)); -	if (error) -		goto out_end_trans; - -out_end_trans: -	gfs2_trans_end(sdp); -out_ipreserv: -	if (alloc_required) -		gfs2_inplace_release(ndip); -out_gunlock_q: -	if (alloc_required) -		gfs2_quota_unlock(ndip); -out_alloc: -	if (alloc_required) -		gfs2_alloc_put(ndip); -out_gunlock: -	while (x--) { -		gfs2_glock_dq(ghs + x); -		gfs2_holder_uninit(ghs + x); -	} -out_gunlock_r: -	if (r_gh.gh_gl) -		gfs2_glock_dq_uninit(&r_gh); -out: -	gfs2_glock_dq_uninit(&ri_gh); -	return error; -} - -/** - * gfs2_follow_link - Follow a symbolic link - * @dentry: The dentry of the link - * @nd: Data that we pass to vfs_follow_link() - * - * This can handle symlinks of any size. - * - * Returns: 0 on success or error code - */ - -static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) -{ -	struct gfs2_inode *ip = GFS2_I(dentry->d_inode); -	struct gfs2_holder i_gh; -	struct buffer_head *dibh; -	unsigned int x, size; -	char *buf; -	int error; - -	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); -	error = gfs2_glock_nq(&i_gh); -	if (error) { -		gfs2_holder_uninit(&i_gh); -		nd_set_link(nd, ERR_PTR(error)); -		return NULL; -	} - -	size = (unsigned int)i_size_read(&ip->i_inode); -	if (size == 0) { -		gfs2_consist_inode(ip); -		buf = ERR_PTR(-EIO); -		goto out; -	} - -	error = gfs2_meta_inode_buffer(ip, &dibh); -	if (error) { -		buf = ERR_PTR(error); -		goto out; -	} - -	x = size + 1; -	buf = kmalloc(x, GFP_NOFS); -	if (!buf) -		buf = ERR_PTR(-ENOMEM); -	else -		memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); -	brelse(dibh); -out: -	gfs2_glock_dq_uninit(&i_gh); -	nd_set_link(nd, buf); -	return NULL; -} - -static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) -{ -	char *s = nd_get_link(nd); -	if (!IS_ERR(s)) -		kfree(s); -} - -/** - * gfs2_permission - - * @inode: - * @mask: - * @nd: passed from Linux VFS, ignored by us - * - * This may be called from the VFS directly, or from within GFS2 with the - * inode locked, so we look to see if the glock is already locked and only - * lock the glock if its not already been done. - * - * Returns: errno - */ - -int gfs2_permission(struct inode *inode, int mask) -{ -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder i_gh; -	int error; -	int unlock = 0; - -	if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { -		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); -		if (error) -			return error; -		unlock = 1; -	} - -	if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) -		error = -EACCES; -	else -		error = generic_permission(inode, mask, gfs2_check_acl); -	if (unlock) -		gfs2_glock_dq_uninit(&i_gh); - -	return error; -} - -static int setattr_chown(struct inode *inode, struct iattr *attr) -{ -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_sbd *sdp = GFS2_SB(inode); -	struct buffer_head *dibh; -	u32 ouid, ogid, nuid, ngid; -	int error; - -	ouid = inode->i_uid; -	ogid = inode->i_gid; -	nuid = attr->ia_uid; -	ngid = attr->ia_gid; - -	if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) -		ouid = nuid = NO_QUOTA_CHANGE; -	if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) -		ogid = ngid = NO_QUOTA_CHANGE; - -	if (!gfs2_alloc_get(ip)) -		return -ENOMEM; - -	error = gfs2_quota_lock(ip, nuid, ngid); -	if (error) -		goto out_alloc; - -	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { -		error = gfs2_quota_check(ip, nuid, ngid); -		if (error) -			goto out_gunlock_q; -	} - -	error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0); -	if (error) -		goto out_gunlock_q; - -	error = gfs2_meta_inode_buffer(ip, &dibh); -	if (error) -		goto out_end_trans; - -	if ((attr->ia_valid & ATTR_SIZE) && -	    attr->ia_size != i_size_read(inode)) { -		int error; - -		error = vmtruncate(inode, attr->ia_size); -		gfs2_assert_warn(sdp, !error); -	} - -	setattr_copy(inode, attr); -	mark_inode_dirty(inode); - -	gfs2_trans_add_bh(ip->i_gl, dibh, 1); -	gfs2_dinode_out(ip, dibh->b_data); -	brelse(dibh); - -	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { -		u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); -		gfs2_quota_change(ip, -blocks, ouid, ogid); -		gfs2_quota_change(ip, blocks, nuid, ngid); -	} - -out_end_trans: -	gfs2_trans_end(sdp); -out_gunlock_q: -	gfs2_quota_unlock(ip); -out_alloc: -	gfs2_alloc_put(ip); -	return error; -} - -/** - * gfs2_setattr - Change attributes on an inode - * @dentry: The dentry which is changing - * @attr: The structure describing the change - * - * The VFS layer wants to change one or more of an inodes attributes.  Write - * that change out to disk. - * - * Returns: errno - */ - -static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) -{ -	struct inode *inode = dentry->d_inode; -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder i_gh; -	int error; - -	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); -	if (error) -		return error; - -	error = -EPERM; -	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) -		goto out; - -	error = inode_change_ok(inode, attr); -	if (error) -		goto out; - -	if (attr->ia_valid & ATTR_SIZE) -		error = gfs2_setattr_size(inode, attr->ia_size); -	else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) -		error = setattr_chown(inode, attr); -	else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) -		error = gfs2_acl_chmod(ip, attr); -	else -		error = gfs2_setattr_simple(ip, attr); - -out: -	gfs2_glock_dq_uninit(&i_gh); -	if (!error) -		mark_inode_dirty(inode); -	return error; -} - -/** - * gfs2_getattr - Read out an inode's attributes - * @mnt: The vfsmount the inode is being accessed from - * @dentry: The dentry to stat - * @stat: The inode's stats - * - * This may be called from the VFS directly, or from within GFS2 with the - * inode locked, so we look to see if the glock is already locked and only - * lock the glock if its not already been done. Note that its the NFS - * readdirplus operation which causes this to be called (from filldir) - * with the glock already held. - * - * Returns: errno - */ - -static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, -			struct kstat *stat) -{ -	struct inode *inode = dentry->d_inode; -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder gh; -	int error; -	int unlock = 0; - -	if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { -		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); -		if (error) -			return error; -		unlock = 1; -	} - -	generic_fillattr(inode, stat); -	if (unlock) -		gfs2_glock_dq_uninit(&gh); - -	return 0; -} - -static int gfs2_setxattr(struct dentry *dentry, const char *name, -			 const void *data, size_t size, int flags) -{ -	struct inode *inode = dentry->d_inode; -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder gh; -	int ret; - -	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); -	ret = gfs2_glock_nq(&gh); -	if (ret == 0) { -		ret = generic_setxattr(dentry, name, data, size, flags); -		gfs2_glock_dq(&gh); -	} -	gfs2_holder_uninit(&gh); -	return ret; -} - -static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, -			     void *data, size_t size) -{ -	struct inode *inode = dentry->d_inode; -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder gh; -	int ret; - -	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); -	ret = gfs2_glock_nq(&gh); -	if (ret == 0) { -		ret = generic_getxattr(dentry, name, data, size); -		gfs2_glock_dq(&gh); -	} -	gfs2_holder_uninit(&gh); -	return ret; -} - -static int gfs2_removexattr(struct dentry *dentry, const char *name) -{ -	struct inode *inode = dentry->d_inode; -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder gh; -	int ret; - -	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); -	ret = gfs2_glock_nq(&gh); -	if (ret == 0) { -		ret = generic_removexattr(dentry, name); -		gfs2_glock_dq(&gh); -	} -	gfs2_holder_uninit(&gh); -	return ret; -} - -static void empty_write_end(struct page *page, unsigned from, -			   unsigned to) -{ -	struct gfs2_inode *ip = GFS2_I(page->mapping->host); - -	page_zero_new_buffers(page, from, to); -	flush_dcache_page(page); -	mark_page_accessed(page); - -	if (!gfs2_is_writeback(ip)) -		gfs2_page_add_databufs(ip, page, from, to); - -	block_commit_write(page, from, to); -} - - -static int write_empty_blocks(struct page *page, unsigned from, unsigned to) -{ -	unsigned start, end, next; -	struct buffer_head *bh, *head; -	int error; - -	if (!page_has_buffers(page)) { -		error = __block_write_begin(page, from, to - from, gfs2_block_map); -		if (unlikely(error)) -			return error; - -		empty_write_end(page, from, to); -		return 0; -	} - -	bh = head = page_buffers(page); -	next = end = 0; -	while (next < from) { -		next += bh->b_size; -		bh = bh->b_this_page; -	} -	start = next; -	do { -		next += bh->b_size; -		if (buffer_mapped(bh)) { -			if (end) { -				error = __block_write_begin(page, start, end - start, -							    gfs2_block_map); -				if (unlikely(error)) -					return error; -				empty_write_end(page, start, end); -				end = 0; -			} -			start = next; -		} -		else -			end = next; -		bh = bh->b_this_page; -	} while (next < to); - -	if (end) { -		error = __block_write_begin(page, start, end - start, gfs2_block_map); -		if (unlikely(error)) -			return error; -		empty_write_end(page, start, end); -	} - -	return 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; -	u64 start = offset >> PAGE_CACHE_SHIFT; -	unsigned int start_offset = offset & ~PAGE_CACHE_MASK; -	u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT; -	pgoff_t curr; -	struct page *page; -	unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK; -	unsigned int from, to; - -	if (!end_offset) -		end_offset = PAGE_CACHE_SIZE; - -	error = gfs2_meta_inode_buffer(ip, &dibh); -	if (unlikely(error)) -		goto out; - -	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; -	} - -	curr = start; -	offset = start << PAGE_CACHE_SHIFT; -	from = start_offset; -	to = PAGE_CACHE_SIZE; -	while (curr <= end) { -		page = grab_cache_page_write_begin(inode->i_mapping, curr, -						   AOP_FLAG_NOFS); -		if (unlikely(!page)) { -			error = -ENOMEM; -			goto out; -		} - -		if (curr == end) -			to = end_offset; -		error = write_empty_blocks(page, from, to); -		if (!error && offset + to > inode->i_size && -		    !(mode & FALLOC_FL_KEEP_SIZE)) { -			i_size_write(inode, offset + to); -		} -		unlock_page(page); -		page_cache_release(page); -		if (error) -			goto out; -		curr++; -		offset += PAGE_CACHE_SIZE; -		from = 0; -	} - -	gfs2_dinode_out(ip, dibh->b_data); -	mark_inode_dirty(inode); - -	brelse(dibh); - -out: -	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_alloc->al_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 inode *inode, int mode, loff_t offset, -			   loff_t len) -{ -	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_alloc *al; -	int error; -	loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; -	next = (next + 1) << sdp->sd_sb.sb_bsize_shift; - -	offset = (offset >> sdp->sd_sb.sb_bsize_shift) << -		 sdp->sd_sb.sb_bsize_shift; - -	len = next - offset; -	bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; -	if (!bytes) -		bytes = UINT_MAX; - -	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; - -	if (!gfs2_write_alloc_required(ip, offset, len)) -		goto out_unlock; - -	while (len > 0) { -		if (len < bytes) -			bytes = len; -		al = gfs2_alloc_get(ip); -		if (!al) { -			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); - -		al->al_requested = data_blocks + ind_blocks; -		error = gfs2_inplace_reserve(ip); -		if (error) { -			if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { -				bytes >>= 1; -				goto retry; -			} -			goto out_qunlock; -		} -		max_bytes = bytes; -		calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks); -		al->al_requested = data_blocks + ind_blocks; - -		rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + -			  RES_RG_HDR + gfs2_rg_blocks(al); -		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_alloc_put(ip); -	} -	goto out_unlock; - -out_trans_fail: -	gfs2_inplace_release(ip); -out_qunlock: -	gfs2_quota_unlock(ip); -out_alloc_put: -	gfs2_alloc_put(ip); -out_unlock: -	gfs2_glock_dq(&ip->i_gh); -out_uninit: -	gfs2_holder_uninit(&ip->i_gh); -	return error; -} - - -static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, -		       u64 start, u64 len) -{ -	struct gfs2_inode *ip = GFS2_I(inode); -	struct gfs2_holder gh; -	int ret; - -	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); -	if (ret) -		return ret; - -	mutex_lock(&inode->i_mutex); - -	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); -	if (ret) -		goto out; - -	if (gfs2_is_stuffed(ip)) { -		u64 phys = ip->i_no_addr << inode->i_blkbits; -		u64 size = i_size_read(inode); -		u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED| -			    FIEMAP_EXTENT_DATA_INLINE; -		phys += sizeof(struct gfs2_dinode); -		phys += start; -		if (start + len > size) -			len = size - start; -		if (start < size) -			ret = fiemap_fill_next_extent(fieinfo, start, phys, -						      len, flags); -		if (ret == 1) -			ret = 0; -	} else { -		ret = __generic_block_fiemap(inode, fieinfo, start, len, -					     gfs2_block_map); -	} - -	gfs2_glock_dq_uninit(&gh); -out: -	mutex_unlock(&inode->i_mutex); -	return ret; -} - -const struct inode_operations gfs2_file_iops = { -	.permission = gfs2_permission, -	.setattr = gfs2_setattr, -	.getattr = gfs2_getattr, -	.setxattr = gfs2_setxattr, -	.getxattr = gfs2_getxattr, -	.listxattr = gfs2_listxattr, -	.removexattr = gfs2_removexattr, -	.fallocate = gfs2_fallocate, -	.fiemap = gfs2_fiemap, -}; - -const struct inode_operations gfs2_dir_iops = { -	.create = gfs2_create, -	.lookup = gfs2_lookup, -	.link = gfs2_link, -	.unlink = gfs2_unlink, -	.symlink = gfs2_symlink, -	.mkdir = gfs2_mkdir, -	.rmdir = gfs2_rmdir, -	.mknod = gfs2_mknod, -	.rename = gfs2_rename, -	.permission = gfs2_permission, -	.setattr = gfs2_setattr, -	.getattr = gfs2_getattr, -	.setxattr = gfs2_setxattr, -	.getxattr = gfs2_getxattr, -	.listxattr = gfs2_listxattr, -	.removexattr = gfs2_removexattr, -	.fiemap = gfs2_fiemap, -}; - -const struct inode_operations gfs2_symlink_iops = { -	.readlink = generic_readlink, -	.follow_link = gfs2_follow_link, -	.put_link = gfs2_put_link, -	.permission = gfs2_permission, -	.setattr = gfs2_setattr, -	.getattr = gfs2_getattr, -	.setxattr = gfs2_setxattr, -	.getxattr = gfs2_getxattr, -	.listxattr = gfs2_listxattr, -	.removexattr = gfs2_removexattr, -	.fiemap = gfs2_fiemap, -}; -  | 
