From 282dc178849882289d30e58b54be6b2799b351aa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:55 +0200 Subject: get rid of cont_write_begin_newtrunc Move the call to vmtruncate to get rid of accessive blocks to the callers in preparation of the new truncate sequence and rename the non-truncating version to cont_write_begin. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/affs/file.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'fs/affs') diff --git a/fs/affs/file.c b/fs/affs/file.c index 322710c3eedf..c4a9875bd1a6 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -406,10 +406,19 @@ static int affs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { + int ret; + *pagep = NULL; - return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, affs_get_block, &AFFS_I(mapping->host)->mmu_private); + if (unlikely(ret)) { + loff_t isize = mapping->host->i_size; + if (pos + len > isize) + vmtruncate(mapping->host, isize); + } + + return ret; } static sector_t _affs_bmap(struct address_space *mapping, sector_t block) -- cgit v1.2.3 From 1025774ce411f2bd4b059ad7b53f0003569b74fa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:30:02 +0200 Subject: remove inode_setattr Replace inode_setattr with opencoded variants of it in all callers. This moves the remaining call to vmtruncate into the filesystem methods where it can be replaced with the proper truncate sequence. In a few cases it was obvious that we would never end up calling vmtruncate so it was left out in the opencoded variant: spufs: explicitly checks for ATTR_SIZE earlier btrfs,hugetlbfs,logfs,dlmfs: explicitly clears ATTR_SIZE earlier ufs: contains an opencoded simple_seattr + truncate that sets the filesize just above In addition to that ncpfs called inode_setattr with handcrafted iattrs, which allowed to trim down the opencoded variant. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- arch/powerpc/platforms/cell/spufs/inode.c | 4 +- drivers/staging/pohmelfs/inode.c | 14 +++-- fs/9p/vfs_inode.c | 15 ++++- fs/affs/inode.c | 13 ++++- fs/attr.c | 25 -------- fs/btrfs/inode.c | 12 ++-- fs/cifs/inode.c | 45 ++++++++++---- fs/exofs/inode.c | 14 ++++- fs/ext3/inode.c | 12 +++- fs/ext4/inode.c | 16 +++-- fs/gfs2/inode.c | 25 +++++--- fs/gfs2/ops_inode.c | 12 +++- fs/gfs2/xattr.c | 24 ++++++-- fs/hfs/inode.c | 12 +++- fs/hfsplus/inode.c | 12 +++- fs/hostfs/hostfs_kern.c | 18 +++++- fs/hpfs/inode.c | 12 +++- fs/hugetlbfs/inode.c | 17 +++--- fs/jfs/file.c | 14 ++++- fs/logfs/file.c | 18 +++--- fs/minix/file.c | 12 +++- fs/ncpfs/inode.c | 24 ++++---- fs/nilfs2/inode.c | 25 ++++++-- fs/ntfs/inode.c | 3 - fs/ocfs2/dlmfs/dlmfs.c | 8 ++- fs/ocfs2/file.c | 16 +++-- fs/omfs/file.c | 12 +++- fs/proc/base.c | 16 ++++- fs/proc/generic.c | 18 ++++-- fs/proc/proc_sysctl.c | 15 ++++- fs/reiserfs/inode.c | 97 +++++++++++++++++-------------- fs/sysv/file.c | 12 +++- fs/udf/file.c | 12 +++- fs/ufs/truncate.c | 5 +- include/linux/fs.h | 1 - 35 files changed, 416 insertions(+), 194 deletions(-) (limited to 'fs/affs') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e5e5f823d687..32625f366fb5 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 643b413d9f0f..e818f53ccfd7 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 4331b3b5ee1c..4b3ad6ac9a41 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; + + 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; + } - 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 f4b2a4ee4f91..6883d5fb84cf 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 aeac826f4774..ed44d8ae8bf1 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 1bff92ad4744..7f9e0536db1a 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 a15b3a9bbff4..9c6a40f5cc57 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 4bb6ef822e46..4bfc1f4fd013 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 5c6f07eefa4a..b04d11936683 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 3da3c9646e5e..1fb390359bc5 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 f03afd9c44bc..6c023a3b5d25 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 98cdd05f3316..d7d410a4ca42 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 82f93da00d1b..776af6eb4bcb 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 8df18e63eb6b..87de671baa83 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 d6ebe53fbdbf..654c5a8ddf1c 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 87ac1891a185..7943ff11d489 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 1042a9bc97f3..3f3b397fd4e6 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 a4e9a7ec3691..d5f019d48b09 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 127263cc8657..c5ce6c1d1ff4 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 #include #include #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 abe1cafbd4c2..23b4d03bbd26 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 7a45dd1fe2e5..4493ce695ab8 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 fa3385154023..b4e8aaae14be 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 5c694ece172e..051d279abb37 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 4b57fb1eac2a..fdef8f729c3a 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 b83d6107a1f5..85e4ccaedd1f 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 2b10b36d1577..584cf8ac167a 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 78c9f0c1a2f3..5542c284dc1c 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 acb7ef80ea4f..a49d9dd06d1d 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 2791907744ed..dd29f0337661 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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 6ff9981f0a18..5be436ea088e 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; + + 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); + 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 045729f5674a..2b8dc5c22867 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3134,55 +3134,62 @@ 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; - - /* (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); + 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; + + 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) error = reiserfs_acl_chmod(inode); diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 94f6319292a1..0a65939508e9 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 7376032c89ce..04bb5bf07630 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 589e01a465ba..085e11623b7b 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 8ebb5f01a418..6ecb83c00a6d 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); -- cgit v1.2.3 From f053ddde7575090e09e2f5c4233d8a19f0925b93 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 6 Jun 2010 10:16:41 -0400 Subject: switch affs to ->evict_inode() Signed-off-by: Al Viro --- fs/affs/affs.h | 3 +-- fs/affs/inode.c | 25 ++++++++++++------------- fs/affs/super.c | 3 +-- 3 files changed, 14 insertions(+), 17 deletions(-) (limited to 'fs/affs') diff --git a/fs/affs/affs.h b/fs/affs/affs.h index f05b6155ccc8..a8cbdeb34025 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -171,8 +171,7 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, extern unsigned long affs_parent_ino(struct inode *dir); extern struct inode *affs_new_inode(struct inode *dir); extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); -extern void affs_delete_inode(struct inode *inode); -extern void affs_clear_inode(struct inode *inode); +extern void affs_evict_inode(struct inode *inode); extern struct inode *affs_iget(struct super_block *sb, unsigned long ino); extern int affs_write_inode(struct inode *inode, diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 6883d5fb84cf..3a0fdec175ba 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -252,23 +252,19 @@ out: } void -affs_delete_inode(struct inode *inode) -{ - pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); - truncate_inode_pages(&inode->i_data, 0); - inode->i_size = 0; - affs_truncate(inode); - clear_inode(inode); - affs_free_block(inode->i_sb, inode->i_ino); -} - -void -affs_clear_inode(struct inode *inode) +affs_evict_inode(struct inode *inode) { unsigned long cache_page; + pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); + truncate_inode_pages(&inode->i_data, 0); - pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); + if (!inode->i_nlink) { + inode->i_size = 0; + affs_truncate(inode); + } + invalidate_inode_buffers(inode); + end_writeback(inode); affs_free_prealloc(inode); cache_page = (unsigned long)AFFS_I(inode)->i_lc; if (cache_page) { @@ -280,6 +276,9 @@ affs_clear_inode(struct inode *inode) affs_brelse(AFFS_I(inode)->i_ext_bh); AFFS_I(inode)->i_ext_last = ~1; AFFS_I(inode)->i_ext_bh = NULL; + + if (!inode->i_nlink) + affs_free_block(inode->i_sb, inode->i_ino); } struct inode * diff --git a/fs/affs/super.c b/fs/affs/super.c index 16a3e4765f68..2c804a87c142 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -140,8 +140,7 @@ static const struct super_operations affs_sops = { .alloc_inode = affs_alloc_inode, .destroy_inode = affs_destroy_inode, .write_inode = affs_write_inode, - .delete_inode = affs_delete_inode, - .clear_inode = affs_clear_inode, + .evict_inode = affs_evict_inode, .put_super = affs_put_super, .write_super = affs_write_super, .sync_fs = affs_sync_fs, -- cgit v1.2.3 From 669d5f1f608f7de29bb467bb239517a414e43777 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 5 Jul 2010 15:14:59 +0300 Subject: AFFS: clean up dirty flag usage In 'affs_write_super()': remove ancient and wrong commented code, remove unneeded 'clean' variable, so the function becomes a bit cleaner and simpler. In 'affs_remount(): remove unnecessary SB dirty flag changes. Tested-by: Artem Bityutskiy Signed-off-by: Artem Bityutskiy Signed-off-by: Al Viro --- fs/affs/super.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'fs/affs') diff --git a/fs/affs/super.c b/fs/affs/super.c index 2c804a87c142..fde3b9ae700f 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -61,20 +61,13 @@ affs_put_super(struct super_block *sb) static void affs_write_super(struct super_block *sb) { - int clean = 2; - lock_super(sb); - if (!(sb->s_flags & MS_RDONLY)) { - // if (sbi->s_bitmap[i].bm_bh) { - // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) { - // clean = 0; - affs_commit_super(sb, clean); - sb->s_dirt = !clean; /* redo until bitmap synced */ - } else - sb->s_dirt = 0; + if (!(sb->s_flags & MS_RDONLY)) + affs_commit_super(sb, 2); + sb->s_dirt = 0; unlock_super(sb); - pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean); + pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds()); } static int @@ -553,9 +546,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) return 0; } if (*flags & MS_RDONLY) { - sb->s_dirt = 1; - while (sb->s_dirt) - affs_write_super(sb); + affs_write_super(sb); affs_free_bitmap(sb); } else res = affs_init_bitmap(sb, flags); -- cgit v1.2.3 From 7435d50611b04c1155a939a9f373154a53606592 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 5 Jul 2010 15:15:00 +0300 Subject: AFFS: wait for sb synchronization when needed AFFS does not ever wait for superblock synchronization in ->put_super(), ->write_super, and ->sync_fs(). However, it should wait for synchronization in ->put_super() because it is about to be unmounted, in ->write_super() because this is periodic SB synchronization performed from a separate kernel thread, and in ->sync_fs() it should respect the 'wait' flag. This patch fixes the situation. Also, in ->put_super(), do not write the SB if it is not dirty. Tested-by: Artem Bityutskiy Signed-off-by: Artem Bityutskiy Signed-off-by: Al Viro --- fs/affs/super.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'fs/affs') diff --git a/fs/affs/super.c b/fs/affs/super.c index fde3b9ae700f..33c4e7eef470 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -26,7 +26,7 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); static int affs_remount (struct super_block *sb, int *flags, char *data); static void -affs_commit_super(struct super_block *sb, int clean) +affs_commit_super(struct super_block *sb, int wait, int clean) { struct affs_sb_info *sbi = AFFS_SB(sb); struct buffer_head *bh = sbi->s_root_bh; @@ -36,6 +36,8 @@ affs_commit_super(struct super_block *sb, int clean) secs_to_datestamp(get_seconds(), &tail->disk_change); affs_fix_checksum(sb, bh); mark_buffer_dirty(bh); + if (wait) + sync_dirty_buffer(bh); } static void @@ -46,8 +48,8 @@ affs_put_super(struct super_block *sb) lock_kernel(); - if (!(sb->s_flags & MS_RDONLY)) - affs_commit_super(sb, 1); + if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt) + affs_commit_super(sb, 1, 1); kfree(sbi->s_prefix); affs_free_bitmap(sb); @@ -63,7 +65,7 @@ affs_write_super(struct super_block *sb) { lock_super(sb); if (!(sb->s_flags & MS_RDONLY)) - affs_commit_super(sb, 2); + affs_commit_super(sb, 1, 2); sb->s_dirt = 0; unlock_super(sb); @@ -74,7 +76,7 @@ static int affs_sync_fs(struct super_block *sb, int wait) { lock_super(sb); - affs_commit_super(sb, 2); + affs_commit_super(sb, wait, 2); sb->s_dirt = 0; unlock_super(sb); return 0; -- cgit v1.2.3