diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2019-09-02 22:06:26 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2019-09-06 19:18:27 -0400 |
commit | cfb9a34d147b8d002d4330ddb53a3eb79565d17c (patch) | |
tree | 0fbaf1e2ee15430ea126ab6bd8db3f13629f2267 | |
parent | e8c82c11c93d586d03d80305959527bcac383555 (diff) |
f2fs: convert inline_data in prior to i_size_write
In below call path, we change i_size before inline conversion, however,
if we failed to convert inline inode, the inode may have wrong i_size
which is larger than max inline size, result inline inode corruption.
- f2fs_setattr
- truncate_setsize
- f2fs_convert_inline_inode
This patch reorders truncate_setsize() and f2fs_convert_inline_inode()
to guarantee inline_data has valid i_size.
Fixes: 0cab80ee0c9e ("f2fs: fix to convert inline inode in ->setattr")
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | fs/f2fs/file.c | 26 |
1 files changed, 13 insertions, 13 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6528216ab832..10927a0b8df3 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -814,14 +814,24 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) | |||
814 | } | 814 | } |
815 | 815 | ||
816 | if (attr->ia_valid & ATTR_SIZE) { | 816 | if (attr->ia_valid & ATTR_SIZE) { |
817 | bool to_smaller = (attr->ia_size <= i_size_read(inode)); | 817 | loff_t old_size = i_size_read(inode); |
818 | |||
819 | if (attr->ia_size > MAX_INLINE_DATA(inode)) { | ||
820 | /* | ||
821 | * should convert inline inode before i_size_write to | ||
822 | * keep smaller than inline_data size with inline flag. | ||
823 | */ | ||
824 | err = f2fs_convert_inline_inode(inode); | ||
825 | if (err) | ||
826 | return err; | ||
827 | } | ||
818 | 828 | ||
819 | down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); | 829 | down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); |
820 | down_write(&F2FS_I(inode)->i_mmap_sem); | 830 | down_write(&F2FS_I(inode)->i_mmap_sem); |
821 | 831 | ||
822 | truncate_setsize(inode, attr->ia_size); | 832 | truncate_setsize(inode, attr->ia_size); |
823 | 833 | ||
824 | if (to_smaller) | 834 | if (attr->ia_size <= old_size) |
825 | err = f2fs_truncate(inode); | 835 | err = f2fs_truncate(inode); |
826 | /* | 836 | /* |
827 | * do not trim all blocks after i_size if target size is | 837 | * do not trim all blocks after i_size if target size is |
@@ -829,21 +839,11 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) | |||
829 | */ | 839 | */ |
830 | up_write(&F2FS_I(inode)->i_mmap_sem); | 840 | up_write(&F2FS_I(inode)->i_mmap_sem); |
831 | up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); | 841 | up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); |
832 | |||
833 | if (err) | 842 | if (err) |
834 | return err; | 843 | return err; |
835 | 844 | ||
836 | if (!to_smaller) { | ||
837 | /* should convert inline inode here */ | ||
838 | if (!f2fs_may_inline_data(inode)) { | ||
839 | err = f2fs_convert_inline_inode(inode); | ||
840 | if (err) | ||
841 | return err; | ||
842 | } | ||
843 | inode->i_mtime = inode->i_ctime = current_time(inode); | ||
844 | } | ||
845 | |||
846 | down_write(&F2FS_I(inode)->i_sem); | 845 | down_write(&F2FS_I(inode)->i_sem); |
846 | inode->i_mtime = inode->i_ctime = current_time(inode); | ||
847 | F2FS_I(inode)->last_disk_size = i_size_read(inode); | 847 | F2FS_I(inode)->last_disk_size = i_size_read(inode); |
848 | up_write(&F2FS_I(inode)->i_sem); | 848 | up_write(&F2FS_I(inode)->i_sem); |
849 | } | 849 | } |