diff options
35 files changed, 416 insertions, 194 deletions
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) | |||
| 110 | if ((attr->ia_valid & ATTR_SIZE) && | 110 | if ((attr->ia_valid & ATTR_SIZE) && |
| 111 | (attr->ia_size != inode->i_size)) | 111 | (attr->ia_size != inode->i_size)) |
| 112 | return -EINVAL; | 112 | return -EINVAL; |
| 113 | return inode_setattr(inode, attr); | 113 | setattr_copy(inode, attr); |
| 114 | mark_inode_dirty(inode); | ||
| 115 | return 0; | ||
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | 118 | ||
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) | |||
| 968 | goto err_out_exit; | 968 | goto err_out_exit; |
| 969 | } | 969 | } |
| 970 | 970 | ||
| 971 | err = inode_setattr(inode, attr); | 971 | if ((attr->ia_valid & ATTR_SIZE) && |
| 972 | if (err) { | 972 | attr->ia_size != i_size_read(inode)) { |
| 973 | dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino); | 973 | err = vmtruncate(inode, attr->ia_size); |
| 974 | goto err_out_exit; | 974 | if (err) { |
| 975 | dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino); | ||
| 976 | goto err_out_exit; | ||
| 977 | } | ||
| 975 | } | 978 | } |
| 976 | 979 | ||
| 980 | setattr_copy(inode, attr); | ||
| 981 | mark_inode_dirty(inode); | ||
| 982 | |||
| 977 | dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n", | 983 | dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n", |
| 978 | __func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode, | 984 | __func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode, |
| 979 | inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size); | 985 | 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) | |||
| 896 | } | 896 | } |
| 897 | 897 | ||
| 898 | retval = p9_client_wstat(fid, &wstat); | 898 | retval = p9_client_wstat(fid, &wstat); |
| 899 | if (retval >= 0) | 899 | if (retval < 0) |
| 900 | retval = inode_setattr(dentry->d_inode, iattr); | 900 | return retval; |
| 901 | |||
| 902 | if ((iattr->ia_valid & ATTR_SIZE) && | ||
| 903 | iattr->ia_size != i_size_read(dentry->d_inode)) { | ||
| 904 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | ||
| 905 | if (retval) | ||
| 906 | return retval; | ||
| 907 | } | ||
| 901 | 908 | ||
| 902 | return retval; | 909 | setattr_copy(dentry->d_inode, iattr); |
| 910 | mark_inode_dirty(dentry->d_inode); | ||
| 911 | return 0; | ||
| 903 | } | 912 | } |
| 904 | 913 | ||
| 905 | /** | 914 | /** |
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) | |||
| 235 | goto out; | 235 | goto out; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | error = inode_setattr(inode, attr); | 238 | if ((attr->ia_valid & ATTR_SIZE) && |
| 239 | if (!error && (attr->ia_valid & ATTR_MODE)) | 239 | attr->ia_size != i_size_read(inode)) { |
| 240 | error = vmtruncate(inode, attr->ia_size); | ||
| 241 | if (error) | ||
| 242 | return error; | ||
| 243 | } | ||
| 244 | |||
| 245 | setattr_copy(inode, attr); | ||
| 246 | mark_inode_dirty(inode); | ||
| 247 | |||
| 248 | if (attr->ia_valid & ATTR_MODE) | ||
| 240 | mode_to_prot(inode); | 249 | mode_to_prot(inode); |
| 241 | out: | 250 | out: |
| 242 | return error; | 251 | return error; |
| @@ -146,31 +146,6 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) | |||
| 146 | } | 146 | } |
| 147 | EXPORT_SYMBOL(setattr_copy); | 147 | EXPORT_SYMBOL(setattr_copy); |
| 148 | 148 | ||
| 149 | /* | ||
| 150 | * note this function is deprecated, the new truncate sequence should be | ||
| 151 | * used instead -- see eg. simple_setsize, setattr_copy. | ||
| 152 | */ | ||
| 153 | int inode_setattr(struct inode *inode, const struct iattr *attr) | ||
| 154 | { | ||
| 155 | unsigned int ia_valid = attr->ia_valid; | ||
| 156 | |||
| 157 | if (ia_valid & ATTR_SIZE && | ||
| 158 | attr->ia_size != i_size_read(inode)) { | ||
| 159 | int error; | ||
| 160 | |||
| 161 | error = vmtruncate(inode, attr->ia_size); | ||
| 162 | if (error) | ||
| 163 | return error; | ||
| 164 | } | ||
| 165 | |||
| 166 | setattr_copy(inode, attr); | ||
| 167 | |||
| 168 | mark_inode_dirty(inode); | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | EXPORT_SYMBOL(inode_setattr); | ||
| 173 | |||
| 174 | int notify_change(struct dentry * dentry, struct iattr * attr) | 149 | int notify_change(struct dentry * dentry, struct iattr * attr) |
| 175 | { | 150 | { |
| 176 | struct inode *inode = dentry->d_inode; | 151 | 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) | |||
| 3656 | if (err) | 3656 | if (err) |
| 3657 | return err; | 3657 | return err; |
| 3658 | } | 3658 | } |
| 3659 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 3660 | 3659 | ||
| 3661 | if (attr->ia_valid) | 3660 | if (attr->ia_valid) { |
| 3662 | err = inode_setattr(inode, attr); | 3661 | setattr_copy(inode, attr); |
| 3662 | mark_inode_dirty(inode); | ||
| 3663 | |||
| 3664 | if (attr->ia_valid & ATTR_MODE) | ||
| 3665 | err = btrfs_acl_chmod(inode); | ||
| 3666 | } | ||
| 3663 | 3667 | ||
| 3664 | if (!err && ((attr->ia_valid & ATTR_MODE))) | ||
| 3665 | err = btrfs_acl_chmod(inode); | ||
| 3666 | return err; | 3668 | return err; |
| 3667 | } | 3669 | } |
| 3668 | 3670 | ||
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) | |||
| 1889 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1889 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1890 | } | 1890 | } |
| 1891 | 1891 | ||
| 1892 | if (!rc) { | 1892 | if (rc) |
| 1893 | rc = inode_setattr(inode, attrs); | 1893 | goto out; |
| 1894 | 1894 | ||
| 1895 | /* force revalidate when any of these times are set since some | 1895 | if ((attrs->ia_valid & ATTR_SIZE) && |
| 1896 | of the fs types (eg ext3, fat) do not have fine enough | 1896 | attrs->ia_size != i_size_read(inode)) { |
| 1897 | time granularity to match protocol, and we do not have a | 1897 | rc = vmtruncate(inode, attrs->ia_size); |
| 1898 | a way (yet) to query the server fs's time granularity (and | 1898 | if (rc) |
| 1899 | whether it rounds times down). | 1899 | goto out; |
| 1900 | */ | ||
| 1901 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | ||
| 1902 | cifsInode->time = 0; | ||
| 1903 | } | 1900 | } |
| 1901 | |||
| 1902 | setattr_copy(inode, attrs); | ||
| 1903 | mark_inode_dirty(inode); | ||
| 1904 | |||
| 1905 | /* force revalidate when any of these times are set since some | ||
| 1906 | of the fs types (eg ext3, fat) do not have fine enough | ||
| 1907 | time granularity to match protocol, and we do not have a | ||
| 1908 | a way (yet) to query the server fs's time granularity (and | ||
| 1909 | whether it rounds times down). | ||
| 1910 | */ | ||
| 1911 | if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) | ||
| 1912 | cifsInode->time = 0; | ||
| 1904 | out: | 1913 | out: |
| 1905 | kfree(args); | 1914 | kfree(args); |
| 1906 | kfree(full_path); | 1915 | kfree(full_path); |
| @@ -2040,8 +2049,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 2040 | 2049 | ||
| 2041 | /* do not need local check to inode_check_ok since the server does | 2050 | /* do not need local check to inode_check_ok since the server does |
| 2042 | that */ | 2051 | that */ |
| 2043 | if (!rc) | 2052 | if (rc) |
| 2044 | rc = inode_setattr(inode, attrs); | 2053 | goto cifs_setattr_exit; |
| 2054 | |||
| 2055 | if ((attrs->ia_valid & ATTR_SIZE) && | ||
| 2056 | attrs->ia_size != i_size_read(inode)) { | ||
| 2057 | rc = vmtruncate(inode, attrs->ia_size); | ||
| 2058 | if (rc) | ||
| 2059 | goto cifs_setattr_exit; | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | setattr_copy(inode, attrs); | ||
| 2063 | mark_inode_dirty(inode); | ||
| 2064 | return 0; | ||
| 2065 | |||
| 2045 | cifs_setattr_exit: | 2066 | cifs_setattr_exit: |
| 2046 | kfree(full_path); | 2067 | kfree(full_path); |
| 2047 | FreeXid(xid); | 2068 | 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) | |||
| 887 | if (error) | 887 | if (error) |
| 888 | return error; | 888 | return error; |
| 889 | 889 | ||
| 890 | error = inode_setattr(inode, iattr); | 890 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 891 | return error; | 891 | iattr->ia_size != i_size_read(inode)) { |
| 892 | int error; | ||
| 893 | |||
| 894 | error = vmtruncate(inode, iattr->ia_size); | ||
| 895 | if (error) | ||
| 896 | return error; | ||
| 897 | } | ||
| 898 | |||
| 899 | setattr_copy(inode, iattr); | ||
| 900 | mark_inode_dirty(inode); | ||
| 901 | return 0; | ||
| 892 | } | 902 | } |
| 893 | 903 | ||
| 894 | static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( | 904 | 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) | |||
| 3208 | ext3_journal_stop(handle); | 3208 | ext3_journal_stop(handle); |
| 3209 | } | 3209 | } |
| 3210 | 3210 | ||
| 3211 | rc = inode_setattr(inode, attr); | 3211 | if ((attr->ia_valid & ATTR_SIZE) && |
| 3212 | attr->ia_size != i_size_read(inode)) { | ||
| 3213 | rc = vmtruncate(inode, attr->ia_size); | ||
| 3214 | if (rc) | ||
| 3215 | goto err_out; | ||
| 3216 | } | ||
| 3217 | |||
| 3218 | setattr_copy(inode, attr); | ||
| 3219 | mark_inode_dirty(inode); | ||
| 3212 | 3220 | ||
| 3213 | if (!rc && (ia_valid & ATTR_MODE)) | 3221 | if (ia_valid & ATTR_MODE) |
| 3214 | rc = ext3_acl_chmod(inode); | 3222 | rc = ext3_acl_chmod(inode); |
| 3215 | 3223 | ||
| 3216 | err_out: | 3224 | 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) | |||
| 5539 | ext4_truncate(inode); | 5539 | ext4_truncate(inode); |
| 5540 | } | 5540 | } |
| 5541 | 5541 | ||
| 5542 | rc = inode_setattr(inode, attr); | 5542 | if ((attr->ia_valid & ATTR_SIZE) && |
| 5543 | attr->ia_size != i_size_read(inode)) | ||
| 5544 | rc = vmtruncate(inode, attr->ia_size); | ||
| 5543 | 5545 | ||
| 5544 | /* If inode_setattr's call to ext4_truncate failed to get a | 5546 | if (!rc) { |
| 5545 | * transaction handle at all, we need to clean up the in-core | 5547 | setattr_copy(inode, attr); |
| 5546 | * orphan list manually. */ | 5548 | mark_inode_dirty(inode); |
| 5549 | } | ||
| 5550 | |||
| 5551 | /* | ||
| 5552 | * If the call to ext4_truncate failed to get a transaction handle at | ||
| 5553 | * all, we need to clean up the in-core orphan list manually. | ||
| 5554 | */ | ||
| 5547 | if (inode->i_nlink) | 5555 | if (inode->i_nlink) |
| 5548 | ext4_orphan_del(NULL, inode); | 5556 | ext4_orphan_del(NULL, inode); |
| 5549 | 5557 | ||
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: | |||
| 991 | 991 | ||
| 992 | static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) | 992 | static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) |
| 993 | { | 993 | { |
| 994 | struct inode *inode = &ip->i_inode; | ||
| 994 | struct buffer_head *dibh; | 995 | struct buffer_head *dibh; |
| 995 | int error; | 996 | int error; |
| 996 | 997 | ||
| 997 | error = gfs2_meta_inode_buffer(ip, &dibh); | 998 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 998 | if (!error) { | 999 | if (error) |
| 999 | error = inode_setattr(&ip->i_inode, attr); | 1000 | return error; |
| 1000 | gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); | 1001 | |
| 1001 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1002 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1002 | gfs2_dinode_out(ip, dibh->b_data); | 1003 | attr->ia_size != i_size_read(inode)) { |
| 1003 | brelse(dibh); | 1004 | error = vmtruncate(inode, attr->ia_size); |
| 1005 | if (error) | ||
| 1006 | return error; | ||
| 1004 | } | 1007 | } |
| 1005 | return error; | 1008 | |
| 1009 | setattr_copy(inode, attr); | ||
| 1010 | mark_inode_dirty(inode); | ||
| 1011 | |||
| 1012 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
| 1013 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
| 1014 | gfs2_dinode_out(ip, dibh->b_data); | ||
| 1015 | brelse(dibh); | ||
| 1016 | return 0; | ||
| 1006 | } | 1017 | } |
| 1007 | 1018 | ||
| 1008 | /** | 1019 | /** |
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) | |||
| 1136 | if (error) | 1136 | if (error) |
| 1137 | goto out_end_trans; | 1137 | goto out_end_trans; |
| 1138 | 1138 | ||
| 1139 | error = inode_setattr(inode, attr); | 1139 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1140 | gfs2_assert_warn(sdp, !error); | 1140 | attr->ia_size != i_size_read(inode)) { |
| 1141 | int error; | ||
| 1142 | |||
| 1143 | error = vmtruncate(inode, attr->ia_size); | ||
| 1144 | gfs2_assert_warn(sdp, !error); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | setattr_copy(inode, attr); | ||
| 1148 | mark_inode_dirty(inode); | ||
| 1141 | 1149 | ||
| 1142 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1150 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 1143 | gfs2_dinode_out(ip, dibh->b_data); | 1151 | 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: | |||
| 1296 | 1296 | ||
| 1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | 1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) |
| 1298 | { | 1298 | { |
| 1299 | struct inode *inode = &ip->i_inode; | ||
| 1299 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1300 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
| 1300 | struct gfs2_ea_location el; | 1301 | struct gfs2_ea_location el; |
| 1301 | struct buffer_head *dibh; | 1302 | struct buffer_head *dibh; |
| @@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | |||
| 1321 | return error; | 1322 | return error; |
| 1322 | 1323 | ||
| 1323 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1324 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 1324 | if (!error) { | 1325 | if (error) |
| 1325 | error = inode_setattr(&ip->i_inode, attr); | 1326 | goto out_trans_end; |
| 1326 | gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); | 1327 | |
| 1327 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1328 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1328 | gfs2_dinode_out(ip, dibh->b_data); | 1329 | attr->ia_size != i_size_read(inode)) { |
| 1329 | brelse(dibh); | 1330 | int error; |
| 1331 | |||
| 1332 | error = vmtruncate(inode, attr->ia_size); | ||
| 1333 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
| 1330 | } | 1334 | } |
| 1331 | 1335 | ||
| 1336 | setattr_copy(inode, attr); | ||
| 1337 | mark_inode_dirty(inode); | ||
| 1338 | |||
| 1339 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
| 1340 | gfs2_dinode_out(ip, dibh->b_data); | ||
| 1341 | brelse(dibh); | ||
| 1342 | |||
| 1343 | out_trans_end: | ||
| 1332 | gfs2_trans_end(sdp); | 1344 | gfs2_trans_end(sdp); |
| 1333 | return error; | 1345 | return error; |
| 1334 | } | 1346 | } |
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) | |||
| 612 | attr->ia_mode = inode->i_mode & ~S_IWUGO; | 612 | attr->ia_mode = inode->i_mode & ~S_IWUGO; |
| 613 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; | 613 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; |
| 614 | } | 614 | } |
| 615 | error = inode_setattr(inode, attr); | ||
| 616 | if (error) | ||
| 617 | return error; | ||
| 618 | 615 | ||
| 616 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 617 | attr->ia_size != i_size_read(inode)) { | ||
| 618 | error = vmtruncate(inode, attr->ia_size); | ||
| 619 | if (error) | ||
| 620 | return error; | ||
| 621 | } | ||
| 622 | |||
| 623 | setattr_copy(inode, attr); | ||
| 624 | mark_inode_dirty(inode); | ||
| 619 | return 0; | 625 | return 0; |
| 620 | } | 626 | } |
| 621 | 627 | ||
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) | |||
| 298 | error = inode_change_ok(inode, attr); | 298 | error = inode_change_ok(inode, attr); |
| 299 | if (error) | 299 | if (error) |
| 300 | return error; | 300 | return error; |
| 301 | return inode_setattr(inode, attr); | 301 | |
| 302 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 303 | attr->ia_size != i_size_read(inode)) { | ||
| 304 | error = vmtruncate(inode, attr->ia_size); | ||
| 305 | if (error) | ||
| 306 | return error; | ||
| 307 | } | ||
| 308 | |||
| 309 | setattr_copy(inode, attr); | ||
| 310 | mark_inode_dirty(inode); | ||
| 311 | return 0; | ||
| 302 | } | 312 | } |
| 303 | 313 | ||
| 304 | static const struct inode_operations hfsplus_file_inode_operations = { | 314 | 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) | |||
| 849 | 849 | ||
| 850 | int hostfs_setattr(struct dentry *dentry, struct iattr *attr) | 850 | int hostfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 851 | { | 851 | { |
| 852 | struct inode *inode = dentry->d_inode; | ||
| 852 | struct hostfs_iattr attrs; | 853 | struct hostfs_iattr attrs; |
| 853 | char *name; | 854 | char *name; |
| 854 | int err; | 855 | int err; |
| 855 | 856 | ||
| 856 | int fd = HOSTFS_I(dentry->d_inode)->fd; | 857 | int fd = HOSTFS_I(inode)->fd; |
| 857 | 858 | ||
| 858 | err = inode_change_ok(dentry->d_inode, attr); | 859 | err = inode_change_ok(inode, attr); |
| 859 | if (err) | 860 | if (err) |
| 860 | return err; | 861 | return err; |
| 861 | 862 | ||
| @@ -905,7 +906,18 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 905 | if (err) | 906 | if (err) |
| 906 | return err; | 907 | return err; |
| 907 | 908 | ||
| 908 | return inode_setattr(dentry->d_inode, attr); | 909 | if ((attr->ia_valid & ATTR_SIZE) && |
| 910 | attr->ia_size != i_size_read(inode)) { | ||
| 911 | int error; | ||
| 912 | |||
| 913 | error = vmtruncate(inode, attr->ia_size); | ||
| 914 | if (err) | ||
| 915 | return err; | ||
| 916 | } | ||
| 917 | |||
| 918 | setattr_copy(inode, attr); | ||
| 919 | mark_inode_dirty(inode); | ||
| 920 | return 0; | ||
| 909 | } | 921 | } |
| 910 | 922 | ||
| 911 | static const struct inode_operations hostfs_iops = { | 923 | 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) | |||
| 277 | if (error) | 277 | if (error) |
| 278 | goto out_unlock; | 278 | goto out_unlock; |
| 279 | 279 | ||
| 280 | error = inode_setattr(inode, attr); | 280 | if ((attr->ia_valid & ATTR_SIZE) && |
| 281 | if (error) | 281 | attr->ia_size != i_size_read(inode)) { |
| 282 | goto out_unlock; | 282 | error = vmtruncate(inode, attr->ia_size); |
| 283 | if (error) | ||
| 284 | return error; | ||
| 285 | } | ||
| 286 | |||
| 287 | setattr_copy(inode, attr); | ||
| 288 | mark_inode_dirty(inode); | ||
| 283 | 289 | ||
| 284 | hpfs_write_inode(inode); | 290 | hpfs_write_inode(inode); |
| 285 | 291 | ||
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) | |||
| 448 | 448 | ||
| 449 | error = inode_change_ok(inode, attr); | 449 | error = inode_change_ok(inode, attr); |
| 450 | if (error) | 450 | if (error) |
| 451 | goto out; | 451 | return error; |
| 452 | 452 | ||
| 453 | if (ia_valid & ATTR_SIZE) { | 453 | if (ia_valid & ATTR_SIZE) { |
| 454 | error = -EINVAL; | 454 | error = -EINVAL; |
| 455 | if (!(attr->ia_size & ~huge_page_mask(h))) | 455 | if (attr->ia_size & ~huge_page_mask(h)) |
| 456 | error = hugetlb_vmtruncate(inode, attr->ia_size); | 456 | return -EINVAL; |
| 457 | error = hugetlb_vmtruncate(inode, attr->ia_size); | ||
| 457 | if (error) | 458 | if (error) |
| 458 | goto out; | 459 | return error; |
| 459 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 460 | } | 460 | } |
| 461 | error = inode_setattr(inode, attr); | 461 | |
| 462 | out: | 462 | setattr_copy(inode, attr); |
| 463 | return error; | 463 | mark_inode_dirty(inode); |
| 464 | return 0; | ||
| 464 | } | 465 | } |
| 465 | 466 | ||
| 466 | static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, | 467 | 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 @@ | |||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/mm.h> | ||
| 20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
| 21 | #include <linux/quotaops.h> | 22 | #include <linux/quotaops.h> |
| 22 | #include "jfs_incore.h" | 23 | #include "jfs_incore.h" |
| @@ -107,11 +108,18 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 107 | return rc; | 108 | return rc; |
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | rc = inode_setattr(inode, iattr); | 111 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 112 | iattr->ia_size != i_size_read(inode)) { | ||
| 113 | rc = vmtruncate(inode, iattr->ia_size); | ||
| 114 | if (rc) | ||
| 115 | return rc; | ||
| 116 | } | ||
| 111 | 117 | ||
| 112 | if (!rc && (iattr->ia_valid & ATTR_MODE)) | 118 | setattr_copy(inode, iattr); |
| 113 | rc = jfs_acl_chmod(inode); | 119 | mark_inode_dirty(inode); |
| 114 | 120 | ||
| 121 | if (iattr->ia_valid & ATTR_MODE) | ||
| 122 | rc = jfs_acl_chmod(inode); | ||
| 115 | return rc; | 123 | return rc; |
| 116 | } | 124 | } |
| 117 | 125 | ||
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) | |||
| 232 | struct inode *inode = dentry->d_inode; | 232 | struct inode *inode = dentry->d_inode; |
| 233 | int err = 0; | 233 | int err = 0; |
| 234 | 234 | ||
| 235 | if (attr->ia_valid & ATTR_SIZE) | 235 | if (attr->ia_valid & ATTR_SIZE) { |
| 236 | err = logfs_truncate(inode, attr->ia_size); | 236 | err = logfs_truncate(inode, attr->ia_size); |
| 237 | attr->ia_valid &= ~ATTR_SIZE; | 237 | if (err) |
| 238 | return err; | ||
| 239 | } | ||
| 238 | 240 | ||
| 239 | if (!err) | 241 | err = inode_change_ok(inode, attr); |
| 240 | err = inode_change_ok(inode, attr); | 242 | if (err) |
| 241 | if (!err) | 243 | return err; |
| 242 | err = inode_setattr(inode, attr); | 244 | |
| 243 | return err; | 245 | setattr_copy(inode, attr); |
| 246 | mark_inode_dirty(inode); | ||
| 247 | return 0; | ||
| 244 | } | 248 | } |
| 245 | 249 | ||
| 246 | const struct inode_operations logfs_reg_iops = { | 250 | 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) | |||
| 31 | error = inode_change_ok(inode, attr); | 31 | error = inode_change_ok(inode, attr); |
| 32 | if (error) | 32 | if (error) |
| 33 | return error; | 33 | return error; |
| 34 | return inode_setattr(inode, attr); | 34 | |
| 35 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 36 | attr->ia_size != i_size_read(inode)) { | ||
| 37 | error = vmtruncate(inode, attr->ia_size); | ||
| 38 | if (error) | ||
| 39 | return error; | ||
| 40 | } | ||
| 41 | |||
| 42 | setattr_copy(inode, attr); | ||
| 43 | mark_inode_dirty(inode); | ||
| 44 | return 0; | ||
| 35 | } | 45 | } |
| 36 | 46 | ||
| 37 | const struct inode_operations minix_file_inode_operations = { | 47 | 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) | |||
| 924 | tmpattr.ia_valid = ATTR_MODE; | 924 | tmpattr.ia_valid = ATTR_MODE; |
| 925 | tmpattr.ia_mode = attr->ia_mode; | 925 | tmpattr.ia_mode = attr->ia_mode; |
| 926 | 926 | ||
| 927 | result = inode_setattr(inode, &tmpattr); | 927 | setattr_copy(inode, &tmpattr); |
| 928 | if (result) | 928 | mark_inode_dirty(inode); |
| 929 | goto out; | ||
| 930 | } | 929 | } |
| 931 | } | 930 | } |
| 932 | #endif | 931 | #endif |
| @@ -954,15 +953,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 954 | result = ncp_make_closed(inode); | 953 | result = ncp_make_closed(inode); |
| 955 | if (result) | 954 | if (result) |
| 956 | goto out; | 955 | goto out; |
| 957 | { | 956 | |
| 958 | struct iattr tmpattr; | 957 | if (attr->ia_size != i_size_read(inode)) { |
| 959 | 958 | result = vmtruncate(inode, attr->ia_size); | |
| 960 | tmpattr.ia_valid = ATTR_SIZE; | ||
| 961 | tmpattr.ia_size = attr->ia_size; | ||
| 962 | |||
| 963 | result = inode_setattr(inode, &tmpattr); | ||
| 964 | if (result) | 959 | if (result) |
| 965 | goto out; | 960 | goto out; |
| 961 | mark_inode_dirty(inode); | ||
| 966 | } | 962 | } |
| 967 | } | 963 | } |
| 968 | if ((attr->ia_valid & ATTR_CTIME) != 0) { | 964 | if ((attr->ia_valid & ATTR_CTIME) != 0) { |
| @@ -1002,8 +998,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 1002 | NCP_FINFO(inode)->nwattr = info.attributes; | 998 | NCP_FINFO(inode)->nwattr = info.attributes; |
| 1003 | #endif | 999 | #endif |
| 1004 | } | 1000 | } |
| 1005 | if (!result) | 1001 | if (result) |
| 1006 | result = inode_setattr(inode, attr); | 1002 | goto out; |
| 1003 | |||
| 1004 | setattr_copy(inode, attr); | ||
| 1005 | mark_inode_dirty(inode); | ||
| 1006 | |||
| 1007 | out: | 1007 | out: |
| 1008 | unlock_kernel(); | 1008 | unlock_kernel(); |
| 1009 | return result; | 1009 | 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) | |||
| 656 | err = nilfs_transaction_begin(sb, &ti, 0); | 656 | err = nilfs_transaction_begin(sb, &ti, 0); |
| 657 | if (unlikely(err)) | 657 | if (unlikely(err)) |
| 658 | return err; | 658 | return err; |
| 659 | err = inode_setattr(inode, iattr); | 659 | |
| 660 | if (!err && (iattr->ia_valid & ATTR_MODE)) | 660 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 661 | iattr->ia_size != i_size_read(inode)) { | ||
| 662 | err = vmtruncate(inode, iattr->ia_size); | ||
| 663 | if (unlikely(err)) | ||
| 664 | goto out_err; | ||
| 665 | } | ||
| 666 | |||
| 667 | setattr_copy(inode, iattr); | ||
| 668 | mark_inode_dirty(inode); | ||
| 669 | |||
| 670 | if (iattr->ia_valid & ATTR_MODE) { | ||
| 661 | err = nilfs_acl_chmod(inode); | 671 | err = nilfs_acl_chmod(inode); |
| 662 | if (likely(!err)) | 672 | if (unlikely(err)) |
| 663 | err = nilfs_transaction_commit(sb); | 673 | goto out_err; |
| 664 | else | 674 | } |
| 665 | nilfs_transaction_abort(sb); | 675 | |
| 676 | return nilfs_transaction_commit(sb); | ||
| 666 | 677 | ||
| 678 | out_err: | ||
| 679 | nilfs_transaction_abort(sb); | ||
| 667 | return err; | 680 | return err; |
| 668 | } | 681 | } |
| 669 | 682 | ||
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) { | |||
| 2879 | * | 2879 | * |
| 2880 | * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also | 2880 | * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also |
| 2881 | * called with ->i_alloc_sem held for writing. | 2881 | * called with ->i_alloc_sem held for writing. |
| 2882 | * | ||
| 2883 | * Basically this is a copy of generic notify_change() and inode_setattr() | ||
| 2884 | * functionality, except we intercept and abort changes in i_size. | ||
| 2885 | */ | 2882 | */ |
| 2886 | int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | 2883 | int ntfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 2887 | { | 2884 | { |
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) | |||
| 214 | 214 | ||
| 215 | attr->ia_valid &= ~ATTR_SIZE; | 215 | attr->ia_valid &= ~ATTR_SIZE; |
| 216 | error = inode_change_ok(inode, attr); | 216 | error = inode_change_ok(inode, attr); |
| 217 | if (!error) | 217 | if (error) |
| 218 | error = inode_setattr(inode, attr); | 218 | return error; |
| 219 | 219 | ||
| 220 | return error; | 220 | setattr_copy(inode, attr); |
| 221 | mark_inode_dirty(inode); | ||
| 222 | return 0; | ||
| 221 | } | 223 | } |
| 222 | 224 | ||
| 223 | static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait) | 225 | 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) | |||
| 1238 | * Otherwise, we could get into problems with truncate as | 1238 | * Otherwise, we could get into problems with truncate as |
| 1239 | * ip_alloc_sem is used there to protect against i_size | 1239 | * ip_alloc_sem is used there to protect against i_size |
| 1240 | * changes. | 1240 | * changes. |
| 1241 | * | ||
| 1242 | * XXX: this means the conditional below can probably be removed. | ||
| 1241 | */ | 1243 | */ |
| 1242 | status = inode_setattr(inode, attr); | 1244 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1243 | if (status < 0) { | 1245 | attr->ia_size != i_size_read(inode)) { |
| 1244 | mlog_errno(status); | 1246 | status = vmtruncate(inode, attr->ia_size); |
| 1245 | goto bail_commit; | 1247 | if (status) { |
| 1248 | mlog_errno(status); | ||
| 1249 | goto bail_commit; | ||
| 1250 | } | ||
| 1246 | } | 1251 | } |
| 1247 | 1252 | ||
| 1253 | setattr_copy(inode, attr); | ||
| 1254 | mark_inode_dirty(inode); | ||
| 1255 | |||
| 1248 | status = ocfs2_mark_inode_dirty(handle, inode, bh); | 1256 | status = ocfs2_mark_inode_dirty(handle, inode, bh); |
| 1249 | if (status < 0) | 1257 | if (status < 0) |
| 1250 | mlog_errno(status); | 1258 | 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) | |||
| 349 | error = inode_change_ok(inode, attr); | 349 | error = inode_change_ok(inode, attr); |
| 350 | if (error) | 350 | if (error) |
| 351 | return error; | 351 | return error; |
| 352 | return inode_setattr(inode, attr); | 352 | |
| 353 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 354 | attr->ia_size != i_size_read(inode)) { | ||
| 355 | error = vmtruncate(inode, attr->ia_size); | ||
| 356 | if (error) | ||
| 357 | return error; | ||
| 358 | } | ||
| 359 | |||
| 360 | setattr_copy(inode, attr); | ||
| 361 | mark_inode_dirty(inode); | ||
| 362 | return 0; | ||
| 353 | } | 363 | } |
| 354 | 364 | ||
| 355 | const struct inode_operations omfs_file_inops = { | 365 | 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) | |||
| 561 | return -EPERM; | 561 | return -EPERM; |
| 562 | 562 | ||
| 563 | error = inode_change_ok(inode, attr); | 563 | error = inode_change_ok(inode, attr); |
| 564 | if (!error) | 564 | if (error) |
| 565 | error = inode_setattr(inode, attr); | 565 | return error; |
| 566 | return error; | 566 | |
| 567 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 568 | attr->ia_size != i_size_read(inode)) { | ||
| 569 | error = vmtruncate(inode, attr->ia_size); | ||
| 570 | if (error) | ||
| 571 | return error; | ||
| 572 | } | ||
| 573 | |||
| 574 | setattr_copy(inode, attr); | ||
| 575 | mark_inode_dirty(inode); | ||
| 576 | return 0; | ||
| 567 | } | 577 | } |
| 568 | 578 | ||
| 569 | static const struct inode_operations proc_def_inode_operations = { | 579 | 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 @@ | |||
| 12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| 13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
| 14 | #include <linux/stat.h> | 14 | #include <linux/stat.h> |
| 15 | #include <linux/mm.h> | ||
| 15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 17 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
| @@ -258,17 +259,22 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) | |||
| 258 | 259 | ||
| 259 | error = inode_change_ok(inode, iattr); | 260 | error = inode_change_ok(inode, iattr); |
| 260 | if (error) | 261 | if (error) |
| 261 | goto out; | 262 | return error; |
| 262 | 263 | ||
| 263 | error = inode_setattr(inode, iattr); | 264 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 264 | if (error) | 265 | iattr->ia_size != i_size_read(inode)) { |
| 265 | goto out; | 266 | error = vmtruncate(inode, iattr->ia_size); |
| 267 | if (error) | ||
| 268 | return error; | ||
| 269 | } | ||
| 270 | |||
| 271 | setattr_copy(inode, iattr); | ||
| 272 | mark_inode_dirty(inode); | ||
| 266 | 273 | ||
| 267 | de->uid = inode->i_uid; | 274 | de->uid = inode->i_uid; |
| 268 | de->gid = inode->i_gid; | 275 | de->gid = inode->i_gid; |
| 269 | de->mode = inode->i_mode; | 276 | de->mode = inode->i_mode; |
| 270 | out: | 277 | return 0; |
| 271 | return error; | ||
| 272 | } | 278 | } |
| 273 | 279 | ||
| 274 | static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, | 280 | 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) | |||
| 329 | return -EPERM; | 329 | return -EPERM; |
| 330 | 330 | ||
| 331 | error = inode_change_ok(inode, attr); | 331 | error = inode_change_ok(inode, attr); |
| 332 | if (!error) | 332 | if (error) |
| 333 | error = inode_setattr(inode, attr); | 333 | return error; |
| 334 | |||
| 335 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 336 | attr->ia_size != i_size_read(inode)) { | ||
| 337 | error = vmtruncate(inode, attr->ia_size); | ||
| 338 | if (error) | ||
| 339 | return error; | ||
| 340 | } | ||
| 334 | 341 | ||
| 335 | return error; | 342 | setattr_copy(inode, attr); |
| 343 | mark_inode_dirty(inode); | ||
| 344 | return 0; | ||
| 336 | } | 345 | } |
| 337 | 346 | ||
| 338 | static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 347 | 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) | |||
| 3134 | } | 3134 | } |
| 3135 | 3135 | ||
| 3136 | error = inode_change_ok(inode, attr); | 3136 | error = inode_change_ok(inode, attr); |
| 3137 | if (!error) { | 3137 | if (error) |
| 3138 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 3138 | goto out; |
| 3139 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | ||
| 3140 | error = reiserfs_chown_xattrs(inode, attr); | ||
| 3141 | 3139 | ||
| 3142 | if (!error) { | 3140 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
| 3143 | struct reiserfs_transaction_handle th; | 3141 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { |
| 3144 | int jbegin_count = | 3142 | struct reiserfs_transaction_handle th; |
| 3145 | 2 * | 3143 | int jbegin_count = |
| 3146 | (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + | 3144 | 2 * |
| 3147 | REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + | 3145 | (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + |
| 3148 | 2; | 3146 | REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + |
| 3149 | 3147 | 2; | |
| 3150 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ | 3148 | |
| 3151 | error = | 3149 | error = reiserfs_chown_xattrs(inode, attr); |
| 3152 | journal_begin(&th, inode->i_sb, | 3150 | |
| 3153 | jbegin_count); | 3151 | if (error) |
| 3154 | if (error) | 3152 | return error; |
| 3155 | goto out; | 3153 | |
| 3156 | error = dquot_transfer(inode, attr); | 3154 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ |
| 3157 | if (error) { | 3155 | error = journal_begin(&th, inode->i_sb, jbegin_count); |
| 3158 | journal_end(&th, inode->i_sb, | 3156 | if (error) |
| 3159 | jbegin_count); | 3157 | goto out; |
| 3160 | goto out; | 3158 | error = dquot_transfer(inode, attr); |
| 3161 | } | 3159 | if (error) { |
| 3162 | /* Update corresponding info in inode so that everything is in | 3160 | journal_end(&th, inode->i_sb, jbegin_count); |
| 3163 | * one transaction */ | 3161 | goto out; |
| 3164 | if (attr->ia_valid & ATTR_UID) | ||
| 3165 | inode->i_uid = attr->ia_uid; | ||
| 3166 | if (attr->ia_valid & ATTR_GID) | ||
| 3167 | inode->i_gid = attr->ia_gid; | ||
| 3168 | mark_inode_dirty(inode); | ||
| 3169 | error = | ||
| 3170 | journal_end(&th, inode->i_sb, jbegin_count); | ||
| 3171 | } | ||
| 3172 | } | ||
| 3173 | if (!error) { | ||
| 3174 | /* | ||
| 3175 | * Relax the lock here, as it might truncate the | ||
| 3176 | * inode pages and wait for inode pages locks. | ||
| 3177 | * To release such page lock, the owner needs the | ||
| 3178 | * reiserfs lock | ||
| 3179 | */ | ||
| 3180 | reiserfs_write_unlock_once(inode->i_sb, depth); | ||
| 3181 | error = inode_setattr(inode, attr); | ||
| 3182 | depth = reiserfs_write_lock_once(inode->i_sb); | ||
| 3183 | } | 3162 | } |
| 3163 | |||
| 3164 | /* Update corresponding info in inode so that everything is in | ||
| 3165 | * one transaction */ | ||
| 3166 | if (attr->ia_valid & ATTR_UID) | ||
| 3167 | inode->i_uid = attr->ia_uid; | ||
| 3168 | if (attr->ia_valid & ATTR_GID) | ||
| 3169 | inode->i_gid = attr->ia_gid; | ||
| 3170 | mark_inode_dirty(inode); | ||
| 3171 | error = journal_end(&th, inode->i_sb, jbegin_count); | ||
| 3172 | if (error) | ||
| 3173 | goto out; | ||
| 3184 | } | 3174 | } |
| 3185 | 3175 | ||
| 3176 | /* | ||
| 3177 | * Relax the lock here, as it might truncate the | ||
| 3178 | * inode pages and wait for inode pages locks. | ||
| 3179 | * To release such page lock, the owner needs the | ||
| 3180 | * reiserfs lock | ||
| 3181 | */ | ||
| 3182 | reiserfs_write_unlock_once(inode->i_sb, depth); | ||
| 3183 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 3184 | attr->ia_size != i_size_read(inode)) | ||
| 3185 | error = vmtruncate(inode, attr->ia_size); | ||
| 3186 | |||
| 3187 | if (!error) { | ||
| 3188 | setattr_copy(inode, attr); | ||
| 3189 | mark_inode_dirty(inode); | ||
| 3190 | } | ||
| 3191 | depth = reiserfs_write_lock_once(inode->i_sb); | ||
| 3192 | |||
| 3186 | if (!error && reiserfs_posixacl(inode->i_sb)) { | 3193 | if (!error && reiserfs_posixacl(inode->i_sb)) { |
| 3187 | if (attr->ia_valid & ATTR_MODE) | 3194 | if (attr->ia_valid & ATTR_MODE) |
| 3188 | error = reiserfs_acl_chmod(inode); | 3195 | 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) | |||
| 38 | error = inode_change_ok(inode, attr); | 38 | error = inode_change_ok(inode, attr); |
| 39 | if (error) | 39 | if (error) |
| 40 | return error; | 40 | return error; |
| 41 | return inode_setattr(inode, attr); | 41 | |
| 42 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 43 | attr->ia_size != i_size_read(inode)) { | ||
| 44 | error = vmtruncate(inode, attr->ia_size); | ||
| 45 | if (error) | ||
| 46 | return error; | ||
| 47 | } | ||
| 48 | |||
| 49 | setattr_copy(inode, attr); | ||
| 50 | mark_inode_dirty(inode); | ||
| 51 | return 0; | ||
| 42 | } | 52 | } |
| 43 | 53 | ||
| 44 | const struct inode_operations sysv_file_inode_operations = { | 54 | 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) | |||
| 236 | error = inode_change_ok(inode, attr); | 236 | error = inode_change_ok(inode, attr); |
| 237 | if (error) | 237 | if (error) |
| 238 | return error; | 238 | return error; |
| 239 | return inode_setattr(inode, attr); | 239 | |
| 240 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 241 | attr->ia_size != i_size_read(inode)) { | ||
| 242 | error = vmtruncate(inode, attr->ia_size); | ||
| 243 | if (error) | ||
| 244 | return error; | ||
| 245 | } | ||
| 246 | |||
| 247 | setattr_copy(inode, attr); | ||
| 248 | mark_inode_dirty(inode); | ||
| 249 | return 0; | ||
| 240 | } | 250 | } |
| 241 | 251 | ||
| 242 | const struct inode_operations udf_file_inode_operations = { | 252 | 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) | |||
| 525 | if (error) | 525 | if (error) |
| 526 | return error; | 526 | return error; |
| 527 | } | 527 | } |
| 528 | return inode_setattr(inode, attr); | 528 | |
| 529 | setattr_copy(inode, attr); | ||
| 530 | mark_inode_dirty(inode); | ||
| 531 | return 0; | ||
| 529 | } | 532 | } |
| 530 | 533 | ||
| 531 | const struct inode_operations ufs_file_inode_operations = { | 534 | 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 *, | |||
| 2392 | 2392 | ||
| 2393 | extern int inode_change_ok(const struct inode *, struct iattr *); | 2393 | extern int inode_change_ok(const struct inode *, struct iattr *); |
| 2394 | extern int inode_newsize_ok(const struct inode *, loff_t offset); | 2394 | extern int inode_newsize_ok(const struct inode *, loff_t offset); |
| 2395 | extern int __must_check inode_setattr(struct inode *, const struct iattr *); | ||
| 2396 | extern void setattr_copy(struct inode *inode, const struct iattr *attr); | 2395 | extern void setattr_copy(struct inode *inode, const struct iattr *attr); |
| 2397 | 2396 | ||
| 2398 | extern void file_update_time(struct file *file); | 2397 | extern void file_update_time(struct file *file); |
