diff options
Diffstat (limited to 'fs/gfs2/inode.c')
| -rw-r--r-- | fs/gfs2/inode.c | 118 | 
1 files changed, 78 insertions, 40 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7119504159f1..890588c7fb33 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -149,7 +149,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,  	ip = GFS2_I(inode);  	if (!inode) -		return ERR_PTR(-ENOBUFS); +		return ERR_PTR(-ENOMEM);  	if (inode->i_state & I_NEW) {  		struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -469,14 +469,36 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,  	brelse(dibh);  } +/** + * gfs2_trans_da_blocks - Calculate number of blocks to link inode + * @dip: The directory we are linking into + * @da: The dir add information + * @nr_inodes: The number of inodes involved + * + * This calculate the number of blocks we need to reserve in a + * transaction to link @nr_inodes into a directory. In most cases + * @nr_inodes will be 2 (the directory plus the inode being linked in) + * but in case of rename, 4 may be required. + * + * Returns: Number of blocks + */ + +static unsigned gfs2_trans_da_blks(const struct gfs2_inode *dip, +				   const struct gfs2_diradd *da, +				   unsigned nr_inodes) +{ +	return da->nr_blocks + gfs2_rg_blocks(dip, da->nr_blocks) + +	       (nr_inodes * RES_DINODE) + RES_QUOTA + RES_STATFS; +} +  static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, -		       struct gfs2_inode *ip, int arq) +		       struct gfs2_inode *ip, struct gfs2_diradd *da)  {  	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); -	struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; +	struct gfs2_alloc_parms ap = { .target = da->nr_blocks, };  	int error; -	if (arq) { +	if (da->nr_blocks) {  		error = gfs2_quota_lock_check(dip);  		if (error)  			goto fail_quota_locks; @@ -485,10 +507,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,  		if (error)  			goto fail_quota_locks; -		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + -					 dip->i_rgd->rd_length + -					 2 * RES_DINODE + -					 RES_STATFS + RES_QUOTA, 0); +		error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, da, 2), 0);  		if (error)  			goto fail_ipreserv;  	} else { @@ -497,7 +516,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,  			goto fail_quota_locks;  	} -	error = gfs2_dir_add(&dip->i_inode, name, ip); +	error = gfs2_dir_add(&dip->i_inode, name, ip, da);  	if (error)  		goto fail_end_trans; @@ -560,7 +579,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,  	struct dentry *d;  	int error;  	u32 aflags = 0; -	int arq; +	struct gfs2_diradd da = { .bh = NULL, };  	if (!name->len || name->len > GFS2_FNAMESIZE)  		return -ENAMETOOLONG; @@ -585,6 +604,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,  	error = PTR_ERR(inode);  	if (!IS_ERR(inode)) {  		d = d_splice_alias(inode, dentry); +		error = PTR_ERR(d); +		if (IS_ERR(d)) +			goto fail_gunlock;  		error = 0;  		if (file) {  			if (S_ISREG(inode->i_mode)) { @@ -602,7 +624,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,  		goto fail_gunlock;  	} -	arq = error = gfs2_diradd_alloc_required(dir, name); +	error = gfs2_diradd_alloc_required(dir, name, &da);  	if (error < 0)  		goto fail_gunlock; @@ -690,7 +712,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,  	if (error)  		goto fail_gunlock3; -	error = link_dinode(dip, name, ip, arq); +	error = link_dinode(dip, name, ip, &da);  	if (error)  		goto fail_gunlock3; @@ -719,6 +741,7 @@ fail_free_inode:  	free_inode_nonrcu(inode);  	inode = NULL;  fail_gunlock: +	gfs2_dir_no_add(&da);  	gfs2_glock_dq_uninit(ghs);  	if (inode && !IS_ERR(inode)) {  		clear_nlink(inode); @@ -779,6 +802,11 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,  	}  	d = d_splice_alias(inode, dentry); +	if (IS_ERR(d)) { +		iput(inode); +		gfs2_glock_dq_uninit(&gh); +		return d; +	}  	if (file && S_ISREG(inode->i_mode))  		error = finish_open(file, dentry, gfs2_open_common, opened); @@ -817,7 +845,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,  	struct gfs2_inode *ip = GFS2_I(inode);  	struct gfs2_holder ghs[2];  	struct buffer_head *dibh; -	int alloc_required; +	struct gfs2_diradd da = { .bh = NULL, };  	int error;  	if (S_ISDIR(inode->i_mode)) @@ -872,13 +900,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,  	if (ip->i_inode.i_nlink == (u32)-1)  		goto out_gunlock; -	alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); +	error = gfs2_diradd_alloc_required(dir, &dentry->d_name, &da);  	if (error < 0)  		goto out_gunlock; -	error = 0; -	if (alloc_required) { -		struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; +	if (da.nr_blocks) { +		struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };  		error = gfs2_quota_lock_check(dip);  		if (error)  			goto out_gunlock; @@ -887,10 +914,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,  		if (error)  			goto out_gunlock_q; -		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + -					 gfs2_rg_blocks(dip, sdp->sd_max_dirres) + -					 2 * RES_DINODE + RES_STATFS + -					 RES_QUOTA, 0); +		error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, &da, 2), 0);  		if (error)  			goto out_ipres;  	} else { @@ -903,7 +927,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,  	if (error)  		goto out_end_trans; -	error = gfs2_dir_add(dir, &dentry->d_name, ip); +	error = gfs2_dir_add(dir, &dentry->d_name, ip, &da);  	if (error)  		goto out_brelse; @@ -919,12 +943,13 @@ out_brelse:  out_end_trans:  	gfs2_trans_end(sdp);  out_ipres: -	if (alloc_required) +	if (da.nr_blocks)  		gfs2_inplace_release(dip);  out_gunlock_q: -	if (alloc_required) +	if (da.nr_blocks)  		gfs2_quota_unlock(dip);  out_gunlock: +	gfs2_dir_no_add(&da);  	gfs2_glock_dq(ghs + 1);  out_child:  	gfs2_glock_dq(ghs); @@ -1254,7 +1279,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,  	struct gfs2_rgrpd *nrgd;  	unsigned int num_gh;  	int dir_rename = 0; -	int alloc_required = 0; +	struct gfs2_diradd da = { .nr_blocks = 0, };  	unsigned int x;  	int error; @@ -1388,14 +1413,14 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,  			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; +	if (nip == NULL) { +		error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name, &da); +		if (error) +			goto out_gunlock; +	} -	if (alloc_required) { -		struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; +	if (da.nr_blocks) { +		struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };  		error = gfs2_quota_lock_check(ndip);  		if (error)  			goto out_gunlock; @@ -1404,10 +1429,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,  		if (error)  			goto out_gunlock_q; -		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + -					 gfs2_rg_blocks(ndip, sdp->sd_max_dirres) + -					 4 * RES_DINODE + 4 * RES_LEAF + -					 RES_STATFS + RES_QUOTA + 4, 0); +		error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(ndip, &da, 4) + +					 4 * RES_LEAF + 4, 0);  		if (error)  			goto out_ipreserv;  	} else { @@ -1441,19 +1464,20 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,  	if (error)  		goto out_end_trans; -	error = gfs2_dir_add(ndir, &ndentry->d_name, ip); +	error = gfs2_dir_add(ndir, &ndentry->d_name, ip, &da);  	if (error)  		goto out_end_trans;  out_end_trans:  	gfs2_trans_end(sdp);  out_ipreserv: -	if (alloc_required) +	if (da.nr_blocks)  		gfs2_inplace_release(ndip);  out_gunlock_q: -	if (alloc_required) +	if (da.nr_blocks)  		gfs2_quota_unlock(ndip);  out_gunlock: +	gfs2_dir_no_add(&da);  	while (x--) {  		gfs2_glock_dq(ghs + x);  		gfs2_holder_uninit(ghs + x); @@ -1607,10 +1631,22 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)  	if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid))  		ogid = ngid = NO_GID_QUOTA_CHANGE; -	error = gfs2_quota_lock(ip, nuid, ngid); +	error = get_write_access(inode);  	if (error)  		return error; +	error = gfs2_rs_alloc(ip); +	if (error) +		goto out; + +	error = gfs2_rindex_update(sdp); +	if (error) +		goto out; + +	error = gfs2_quota_lock(ip, nuid, ngid); +	if (error) +		goto out; +  	if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||  	    !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {  		error = gfs2_quota_check(ip, nuid, ngid); @@ -1637,6 +1673,8 @@ out_end_trans:  	gfs2_trans_end(sdp);  out_gunlock_q:  	gfs2_quota_unlock(ip); +out: +	put_write_access(inode);  	return error;  }  |