diff options
35 files changed, 415 insertions, 193 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e5e5f823d68..32625f366fb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -110,7 +110,9 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)  	if ((attr->ia_valid & ATTR_SIZE) &&  	    (attr->ia_size != inode->i_size))  		return -EINVAL; -	return inode_setattr(inode, attr); +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  } diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index 643b413d9f0..e818f53ccfd 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -968,12 +968,18 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)  		goto err_out_exit;  	} -	err = inode_setattr(inode, attr); -	if (err) { -		dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino); -		goto err_out_exit; +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		err = vmtruncate(inode, attr->ia_size); +		if (err) { +			dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino); +			goto err_out_exit; +		}  	} +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +  	dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",  			__func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,  			inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 4331b3b5ee1..4b3ad6ac9a4 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -896,10 +896,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)  	}  	retval = p9_client_wstat(fid, &wstat); -	if (retval >= 0) -		retval = inode_setattr(dentry->d_inode, iattr); +	if (retval < 0) +		return retval; -	return retval; +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(dentry->d_inode)) { +		retval = vmtruncate(dentry->d_inode, iattr->ia_size); +		if (retval) +			return retval; +	} + +	setattr_copy(dentry->d_inode, iattr); +	mark_inode_dirty(dentry->d_inode); +	return 0;  }  /** diff --git a/fs/affs/inode.c b/fs/affs/inode.c index f4b2a4ee4f9..6883d5fb84c 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -235,8 +235,17 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)  		goto out;  	} -	error = inode_setattr(inode, attr); -	if (!error && (attr->ia_valid & ATTR_MODE)) +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); + +	if (attr->ia_valid & ATTR_MODE)  		mode_to_prot(inode);  out:  	return error; diff --git a/fs/attr.c b/fs/attr.c index aeac826f477..ed44d8ae8bf 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -146,31 +146,6 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)  }  EXPORT_SYMBOL(setattr_copy); -/* - * note this function is deprecated, the new truncate sequence should be - * used instead -- see eg. simple_setsize, setattr_copy. - */ -int inode_setattr(struct inode *inode, const struct iattr *attr) -{ -	unsigned int ia_valid = attr->ia_valid; - -	if (ia_valid & ATTR_SIZE && -	    attr->ia_size != i_size_read(inode)) { -		int error; - -		error = vmtruncate(inode, attr->ia_size); -		if (error) -			return error; -	} - -	setattr_copy(inode, attr); - -	mark_inode_dirty(inode); - -	return 0; -} -EXPORT_SYMBOL(inode_setattr); -  int notify_change(struct dentry * dentry, struct iattr * attr)  {  	struct inode *inode = dentry->d_inode; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1bff92ad474..7f9e0536db1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3656,13 +3656,15 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)  		if (err)  			return err;  	} -	attr->ia_valid &= ~ATTR_SIZE; -	if (attr->ia_valid) -		err = inode_setattr(inode, attr); +	if (attr->ia_valid) { +		setattr_copy(inode, attr); +		mark_inode_dirty(inode); + +		if (attr->ia_valid & ATTR_MODE) +			err = btrfs_acl_chmod(inode); +	} -	if (!err && ((attr->ia_valid & ATTR_MODE))) -		err = btrfs_acl_chmod(inode);  	return err;  } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a15b3a9bbff..9c6a40f5cc5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1889,18 +1889,27 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)  					CIFS_MOUNT_MAP_SPECIAL_CHR);  	} -	if (!rc) { -		rc = inode_setattr(inode, attrs); +	if (rc) +		goto out; -		/* force revalidate when any of these times are set since some -		   of the fs types (eg ext3, fat) do not have fine enough -		   time granularity to match protocol, and we do not have a -		   a way (yet) to query the server fs's time granularity (and -		   whether it rounds times down). -		*/ -		if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) -			cifsInode->time = 0; +	if ((attrs->ia_valid & ATTR_SIZE) && +	    attrs->ia_size != i_size_read(inode)) { +		rc = vmtruncate(inode, attrs->ia_size); +		if (rc) +			goto out;  	} + +	setattr_copy(inode, attrs); +	mark_inode_dirty(inode); + +	/* force revalidate when any of these times are set since some +	   of the fs types (eg ext3, fat) do not have fine enough +	   time granularity to match protocol, and we do not have a +	   a way (yet) to query the server fs's time granularity (and +	   whether it rounds times down). +	*/ +	if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) +		cifsInode->time = 0;  out:  	kfree(args);  	kfree(full_path); @@ -2040,8 +2049,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)  	/* do not need local check to inode_check_ok since the server does  	   that */ -	if (!rc) -		rc = inode_setattr(inode, attrs); +	if (rc) +		goto cifs_setattr_exit; + +	if ((attrs->ia_valid & ATTR_SIZE) && +	    attrs->ia_size != i_size_read(inode)) { +		rc = vmtruncate(inode, attrs->ia_size); +		if (rc) +			goto cifs_setattr_exit; +	} + +	setattr_copy(inode, attrs); +	mark_inode_dirty(inode); +	return 0; +  cifs_setattr_exit:  	kfree(full_path);  	FreeXid(xid); diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 4bb6ef822e4..4bfc1f4fd01 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -887,8 +887,18 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)  	if (error)  		return error; -	error = inode_setattr(inode, iattr); -	return error; +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(inode)) { +		int error; + +		error = vmtruncate(inode, iattr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, iattr); +	mark_inode_dirty(inode); +	return 0;  }  static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 5c6f07eefa4..b04d1193668 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3208,9 +3208,17 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)  		ext3_journal_stop(handle);  	} -	rc = inode_setattr(inode, attr); +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		rc = vmtruncate(inode, attr->ia_size); +		if (rc) +			goto err_out; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); -	if (!rc && (ia_valid & ATTR_MODE)) +	if (ia_valid & ATTR_MODE)  		rc = ext3_acl_chmod(inode);  err_out: diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3da3c9646e5..1fb390359bc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5539,11 +5539,19 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)  			ext4_truncate(inode);  	} -	rc = inode_setattr(inode, attr); +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) +		rc = vmtruncate(inode, attr->ia_size); -	/* If inode_setattr's call to ext4_truncate failed to get a -	 * transaction handle at all, we need to clean up the in-core -	 * orphan list manually. */ +	if (!rc) { +		setattr_copy(inode, attr); +		mark_inode_dirty(inode); +	} + +	/* +	 * If the call to ext4_truncate failed to get a transaction handle at +	 * all, we need to clean up the in-core orphan list manually. +	 */  	if (inode->i_nlink)  		ext4_orphan_del(NULL, inode); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f03afd9c44b..6c023a3b5d2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -991,18 +991,29 @@ fail:  static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)  { +	struct inode *inode = &ip->i_inode;  	struct buffer_head *dibh;  	int error;  	error = gfs2_meta_inode_buffer(ip, &dibh); -	if (!error) { -		error = inode_setattr(&ip->i_inode, attr); -		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); -		gfs2_trans_add_bh(ip->i_gl, dibh, 1); -		gfs2_dinode_out(ip, dibh->b_data); -		brelse(dibh); +	if (error) +		return error; + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error;  	} -	return error; + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); + +	gfs2_assert_warn(GFS2_SB(inode), !error); +	gfs2_trans_add_bh(ip->i_gl, dibh, 1); +	gfs2_dinode_out(ip, dibh->b_data); +	brelse(dibh); +	return 0;  }  /** diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 98cdd05f331..d7d410a4ca4 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1136,8 +1136,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)  	if (error)  		goto out_end_trans; -	error = inode_setattr(inode, attr); -	gfs2_assert_warn(sdp, !error); +	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); diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 82f93da00d1..776af6eb4bc 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -1296,6 +1296,7 @@ fail:  int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)  { +	struct inode *inode = &ip->i_inode;  	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);  	struct gfs2_ea_location el;  	struct buffer_head *dibh; @@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)  		return error;  	error = gfs2_meta_inode_buffer(ip, &dibh); -	if (!error) { -		error = inode_setattr(&ip->i_inode, attr); -		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); -		gfs2_trans_add_bh(ip->i_gl, dibh, 1); -		gfs2_dinode_out(ip, dibh->b_data); -		brelse(dibh); +	if (error) +		goto out_trans_end; + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		int error; + +		error = vmtruncate(inode, attr->ia_size); +		gfs2_assert_warn(GFS2_SB(inode), !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); + +out_trans_end:  	gfs2_trans_end(sdp);  	return error;  } diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 8df18e63eb6..87de671baa8 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -612,10 +612,16 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)  			attr->ia_mode = inode->i_mode & ~S_IWUGO;  		attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;  	} -	error = inode_setattr(inode, attr); -	if (error) -		return error; +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode);  	return 0;  } diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index d6ebe53fbdb..654c5a8ddf1 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -298,7 +298,17 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error)  		return error; -	return inode_setattr(inode, attr); + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static const struct inode_operations hfsplus_file_inode_operations = { diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 87ac1891a18..7943ff11d48 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -849,13 +849,14 @@ int hostfs_permission(struct inode *ino, int desired)  int hostfs_setattr(struct dentry *dentry, struct iattr *attr)  { +	struct inode *inode = dentry->d_inode;  	struct hostfs_iattr attrs;  	char *name;  	int err; -	int fd = HOSTFS_I(dentry->d_inode)->fd; +	int fd = HOSTFS_I(inode)->fd; -	err = inode_change_ok(dentry->d_inode, attr); +	err = inode_change_ok(inode, attr);  	if (err)  		return err; @@ -905,7 +906,18 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)  	if (err)  		return err; -	return inode_setattr(dentry->d_inode, attr); +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		int error; + +		error = vmtruncate(inode, attr->ia_size); +		if (err) +			return err; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static const struct inode_operations hostfs_iops = { diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 1042a9bc97f..3f3b397fd4e 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)  	if (error)  		goto out_unlock; -	error = inode_setattr(inode, attr); -	if (error) -		goto out_unlock; +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode);  	hpfs_write_inode(inode); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a4e9a7ec369..d5f019d48b0 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -448,19 +448,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error) -		goto out; +		return error;  	if (ia_valid & ATTR_SIZE) {  		error = -EINVAL; -		if (!(attr->ia_size & ~huge_page_mask(h))) -			error = hugetlb_vmtruncate(inode, attr->ia_size); +		if (attr->ia_size & ~huge_page_mask(h)) +			return -EINVAL; +		error = hugetlb_vmtruncate(inode, attr->ia_size);  		if (error) -			goto out; -		attr->ia_valid &= ~ATTR_SIZE; +			return error;  	} -	error = inode_setattr(inode, attr); -out: -	return error; + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,  diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 127263cc865..c5ce6c1d1ff 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -17,6 +17,7 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */ +#include <linux/mm.h>  #include <linux/fs.h>  #include <linux/quotaops.h>  #include "jfs_incore.h" @@ -107,11 +108,18 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)  			return rc;  	} -	rc = inode_setattr(inode, iattr); +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(inode)) { +		rc = vmtruncate(inode, iattr->ia_size); +		if (rc) +			return rc; +	} -	if (!rc && (iattr->ia_valid & ATTR_MODE)) -		rc = jfs_acl_chmod(inode); +	setattr_copy(inode, iattr); +	mark_inode_dirty(inode); +	if (iattr->ia_valid & ATTR_MODE) +		rc = jfs_acl_chmod(inode);  	return rc;  } diff --git a/fs/logfs/file.c b/fs/logfs/file.c index abe1cafbd4c..23b4d03bbd2 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -232,15 +232,19 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)  	struct inode *inode = dentry->d_inode;  	int err = 0; -	if (attr->ia_valid & ATTR_SIZE) +	if (attr->ia_valid & ATTR_SIZE) {  		err = logfs_truncate(inode, attr->ia_size); -	attr->ia_valid &= ~ATTR_SIZE; +		if (err) +			return err; +	} -	if (!err) -		err = inode_change_ok(inode, attr); -	if (!err) -		err = inode_setattr(inode, attr); -	return err; +	err = inode_change_ok(inode, attr); +	if (err) +		return err; + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations logfs_reg_iops = { diff --git a/fs/minix/file.c b/fs/minix/file.c index 7a45dd1fe2e..4493ce695ab 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -31,7 +31,17 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error)  		return error; -	return inode_setattr(inode, attr); + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations minix_file_inode_operations = { diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index fa338515402..b4e8aaae14b 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -924,9 +924,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  				tmpattr.ia_valid = ATTR_MODE;  				tmpattr.ia_mode = attr->ia_mode; -				result = inode_setattr(inode, &tmpattr); -				if (result) -					goto out; +				setattr_copy(inode, &tmpattr); +				mark_inode_dirty(inode);  			}  		}  #endif @@ -954,15 +953,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  		result = ncp_make_closed(inode);  		if (result)  			goto out; -		{ -			struct iattr tmpattr; -			 -			tmpattr.ia_valid = ATTR_SIZE; -			tmpattr.ia_size = attr->ia_size; -			 -			result = inode_setattr(inode, &tmpattr); + +		if (attr->ia_size != i_size_read(inode)) { +			result = vmtruncate(inode, attr->ia_size);  			if (result)  				goto out; +			mark_inode_dirty(inode);  		}  	}  	if ((attr->ia_valid & ATTR_CTIME) != 0) { @@ -1002,8 +998,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  			NCP_FINFO(inode)->nwattr = info.attributes;  #endif  	} -	if (!result) -		result = inode_setattr(inode, attr); +	if (result) +		goto out; + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +  out:  	unlock_kernel();  	return result; diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 5c694ece172..051d279abb3 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -656,14 +656,27 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)  	err = nilfs_transaction_begin(sb, &ti, 0);  	if (unlikely(err))  		return err; -	err = inode_setattr(inode, iattr); -	if (!err && (iattr->ia_valid & ATTR_MODE)) + +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(inode)) { +		err = vmtruncate(inode, iattr->ia_size); +		if (unlikely(err)) +			goto out_err; +	} + +	setattr_copy(inode, iattr); +	mark_inode_dirty(inode); + +	if (iattr->ia_valid & ATTR_MODE) {  		err = nilfs_acl_chmod(inode); -	if (likely(!err)) -		err = nilfs_transaction_commit(sb); -	else -		nilfs_transaction_abort(sb); +		if (unlikely(err)) +			goto out_err; +	} + +	return nilfs_transaction_commit(sb); +out_err: +	nilfs_transaction_abort(sb);  	return err;  } diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 4b57fb1eac2..fdef8f729c3 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2879,9 +2879,6 @@ void ntfs_truncate_vfs(struct inode *vi) {   *   * Called with ->i_mutex held.  For the ATTR_SIZE (i.e. ->truncate) case, also   * called with ->i_alloc_sem held for writing. - * - * Basically this is a copy of generic notify_change() and inode_setattr() - * functionality, except we intercept and abort changes in i_size.   */  int ntfs_setattr(struct dentry *dentry, struct iattr *attr)  { diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index b83d6107a1f..85e4ccaedd1 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -214,10 +214,12 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)  	attr->ia_valid &= ~ATTR_SIZE;  	error = inode_change_ok(inode, attr); -	if (!error) -		error = inode_setattr(inode, attr); +	if (error) +		return error; -	return error; +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 2b10b36d157..584cf8ac167 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1238,13 +1238,21 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)  	 * Otherwise, we could get into problems with truncate as  	 * ip_alloc_sem is used there to protect against i_size  	 * changes. +	 * +	 * XXX: this means the conditional below can probably be removed.  	 */ -	status = inode_setattr(inode, attr); -	if (status < 0) { -		mlog_errno(status); -		goto bail_commit; +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		status = vmtruncate(inode, attr->ia_size); +		if (status) { +			mlog_errno(status); +			goto bail_commit; +		}  	} +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +  	status = ocfs2_mark_inode_dirty(handle, inode, bh);  	if (status < 0)  		mlog_errno(status); diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 78c9f0c1a2f..5542c284dc1 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -349,7 +349,17 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error)  		return error; -	return inode_setattr(inode, attr); + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations omfs_file_inops = { diff --git a/fs/proc/base.c b/fs/proc/base.c index acb7ef80ea4..a49d9dd06d1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -561,9 +561,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr)  		return -EPERM;  	error = inode_change_ok(inode, attr); -	if (!error) -		error = inode_setattr(inode, attr); -	return error; +	if (error) +		return error; + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static const struct inode_operations proc_def_inode_operations = { diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 2791907744e..dd29f033766 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -12,6 +12,7 @@  #include <linux/time.h>  #include <linux/proc_fs.h>  #include <linux/stat.h> +#include <linux/mm.h>  #include <linux/module.h>  #include <linux/slab.h>  #include <linux/mount.h> @@ -258,17 +259,22 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)  	error = inode_change_ok(inode, iattr);  	if (error) -		goto out; +		return error; -	error = inode_setattr(inode, iattr); -	if (error) -		goto out; +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, iattr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, iattr); +	mark_inode_dirty(inode);  	de->uid = inode->i_uid;  	de->gid = inode->i_gid;  	de->mode = inode->i_mode; -out: -	return error; +	return 0;  }  static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 6ff9981f0a1..5be436ea088 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -329,10 +329,19 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)  		return -EPERM;  	error = inode_change_ok(inode, attr); -	if (!error) -		error = inode_setattr(inode, attr); +	if (error) +		return error; -	return error; +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 045729f5674..2b8dc5c2286 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3134,54 +3134,61 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)  	}  	error = inode_change_ok(inode, attr); -	if (!error) { -		if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -		    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { -			error = reiserfs_chown_xattrs(inode, attr); +	if (error) +		goto out; -			if (!error) { -				struct reiserfs_transaction_handle th; -				int jbegin_count = -				    2 * -				    (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + -				     REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + -				    2; +	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || +	    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { +		struct reiserfs_transaction_handle th; +		int jbegin_count = +		    2 * +		    (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + +		     REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + +		    2; -				/* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ -				error = -				    journal_begin(&th, inode->i_sb, -						  jbegin_count); -				if (error) -					goto out; -				error = dquot_transfer(inode, attr); -				if (error) { -					journal_end(&th, inode->i_sb, -						    jbegin_count); -					goto out; -				} -				/* Update corresponding info in inode so that everything is in -				 * one transaction */ -				if (attr->ia_valid & ATTR_UID) -					inode->i_uid = attr->ia_uid; -				if (attr->ia_valid & ATTR_GID) -					inode->i_gid = attr->ia_gid; -				mark_inode_dirty(inode); -				error = -				    journal_end(&th, inode->i_sb, jbegin_count); -			} -		} -		if (!error) { -			/* -			 * Relax the lock here, as it might truncate the -			 * inode pages and wait for inode pages locks. -			 * To release such page lock, the owner needs the -			 * reiserfs lock -			 */ -			reiserfs_write_unlock_once(inode->i_sb, depth); -			error = inode_setattr(inode, attr); -			depth = reiserfs_write_lock_once(inode->i_sb); +		error = reiserfs_chown_xattrs(inode, attr); + +		if (error) +			return error; + +		/* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ +		error = journal_begin(&th, inode->i_sb, jbegin_count); +		if (error) +			goto out; +		error = dquot_transfer(inode, attr); +		if (error) { +			journal_end(&th, inode->i_sb, jbegin_count); +			goto out;  		} + +		/* Update corresponding info in inode so that everything is in +		 * one transaction */ +		if (attr->ia_valid & ATTR_UID) +			inode->i_uid = attr->ia_uid; +		if (attr->ia_valid & ATTR_GID) +			inode->i_gid = attr->ia_gid; +		mark_inode_dirty(inode); +		error = journal_end(&th, inode->i_sb, jbegin_count); +		if (error) +			goto out; +	} + +	/* +	 * Relax the lock here, as it might truncate the +	 * inode pages and wait for inode pages locks. +	 * To release such page lock, the owner needs the +	 * reiserfs lock +	 */ +	reiserfs_write_unlock_once(inode->i_sb, depth); +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) +		error = vmtruncate(inode, attr->ia_size); + +	if (!error) { +		setattr_copy(inode, attr); +		mark_inode_dirty(inode);  	} +	depth = reiserfs_write_lock_once(inode->i_sb);  	if (!error && reiserfs_posixacl(inode->i_sb)) {  		if (attr->ia_valid & ATTR_MODE) diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 94f6319292a..0a65939508e 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -38,7 +38,17 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error)  		return error; -	return inode_setattr(inode, attr); + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations sysv_file_inode_operations = { diff --git a/fs/udf/file.c b/fs/udf/file.c index 7376032c89c..04bb5bf0763 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -236,7 +236,17 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)  	error = inode_change_ok(inode, attr);  	if (error)  		return error; -	return inode_setattr(inode, attr); + +	if ((attr->ia_valid & ATTR_SIZE) && +	    attr->ia_size != i_size_read(inode)) { +		error = vmtruncate(inode, attr->ia_size); +		if (error) +			return error; +	} + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations udf_file_inode_operations = { diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 589e01a465b..085e11623b7 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -525,7 +525,10 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)  		if (error)  			return error;  	} -	return inode_setattr(inode, attr); + +	setattr_copy(inode, attr); +	mark_inode_dirty(inode); +	return 0;  }  const struct inode_operations ufs_file_inode_operations = { diff --git a/include/linux/fs.h b/include/linux/fs.h index 8ebb5f01a41..6ecb83c00a6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2392,7 +2392,6 @@ extern int buffer_migrate_page(struct address_space *,  extern int inode_change_ok(const struct inode *, struct iattr *);  extern int inode_newsize_ok(const struct inode *, loff_t offset); -extern int __must_check inode_setattr(struct inode *, const struct iattr *);  extern void setattr_copy(struct inode *inode, const struct iattr *attr);  extern void file_update_time(struct file *file);  |