| From dff6efc326a4d5f305797d4a6bba14f374fdd633 Mon Sep 17 00:00:00 2001 |
| From: Christoph Hellwig <hch@infradead.org> |
| Date: Tue, 19 Nov 2013 07:17:07 -0800 |
| Subject: fs: fix iversion handling |
| |
| From: Christoph Hellwig <hch@infradead.org> |
| |
| commit dff6efc326a4d5f305797d4a6bba14f374fdd633 upstream. |
| |
| Currently notify_change directly updates i_version for size updates, |
| which not only is counter to how all other fields are updated through |
| struct iattr, but also breaks XFS, which need inode updates to happen |
| under its own lock, and synchronized to the structure that gets written |
| to the log. |
| |
| Remove the update in the common code, and it to btrfs and ext4, |
| XFS already does a proper updaste internally and currently gets a |
| double update with the existing code. |
| |
| IMHO this is 3.13 and -stable material and should go in through the XFS |
| tree. |
| |
| Signed-off-by: Christoph Hellwig <hch@lst.de> |
| Reviewed-by: Andreas Dilger <adilger@dilger.ca> |
| Acked-by: Jan Kara <jack@suse.cz> |
| Reviewed-by: Dave Chinner <dchinner@redhat.com> |
| Signed-off-by: Chris Mason <clm@fb.com> |
| Signed-off-by: Ben Myers <bpm@sgi.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/attr.c | 5 ----- |
| fs/btrfs/inode.c | 8 ++++++-- |
| fs/ext4/inode.c | 4 ++++ |
| 3 files changed, 10 insertions(+), 7 deletions(-) |
| |
| --- a/fs/attr.c |
| +++ b/fs/attr.c |
| @@ -202,11 +202,6 @@ int notify_change(struct dentry * dentry |
| return -EPERM; |
| } |
| |
| - if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) { |
| - if (attr->ia_size != inode->i_size) |
| - inode_inc_iversion(inode); |
| - } |
| - |
| if ((ia_valid & ATTR_MODE)) { |
| umode_t amode = attr->ia_mode; |
| /* Flag setting protected by i_mutex */ |
| --- a/fs/btrfs/inode.c |
| +++ b/fs/btrfs/inode.c |
| @@ -4354,8 +4354,12 @@ static int btrfs_setsize(struct inode *i |
| * these flags set. For all other operations the VFS set these flags |
| * explicitly if it wants a timestamp update. |
| */ |
| - if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) |
| - inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); |
| + if (newsize != oldsize) { |
| + inode_inc_iversion(inode); |
| + if (!(mask & (ATTR_CTIME | ATTR_MTIME))) |
| + inode->i_ctime = inode->i_mtime = |
| + current_fs_time(inode->i_sb); |
| + } |
| |
| if (newsize > oldsize) { |
| truncate_pagecache(inode, newsize); |
| --- a/fs/ext4/inode.c |
| +++ b/fs/ext4/inode.c |
| @@ -4586,6 +4586,10 @@ int ext4_setattr(struct dentry *dentry, |
| if (attr->ia_size > sbi->s_bitmap_maxbytes) |
| return -EFBIG; |
| } |
| + |
| + if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) |
| + inode_inc_iversion(inode); |
| + |
| if (S_ISREG(inode->i_mode) && |
| (attr->ia_size < inode->i_size)) { |
| if (ext4_should_order_data(inode)) { |