f2fs: truncate page cache before clearing flags when aborting atomic write
authorSunmin Jeong <s_min.jeong@samsung.com>
Wed, 13 Mar 2024 11:26:20 +0000 (20:26 +0900)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 14 Mar 2024 16:08:43 +0000 (09:08 -0700)
In f2fs_do_write_data_page, FI_ATOMIC_FILE flag selects the target inode
between the original inode and COW inode. When aborting atomic write and
writeback occur simultaneously, invalid data can be written to original
inode if the FI_ATOMIC_FILE flag is cleared meanwhile.

To prevent the problem, let's truncate all pages before clearing the flag

Atomic write thread              Writeback thread
  f2fs_abort_atomic_write
    clear_inode_flag(inode, FI_ATOMIC_FILE)
                                  __writeback_single_inode
                                    do_writepages
                                      f2fs_do_write_data_page
                                        - use dn of original inode
    truncate_inode_pages_final

Fixes: 3db1de0e582c ("f2fs: change the current atomic write way")
Cc: stable@vger.kernel.org #v5.19+
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Reviewed-by: Yeongjin Gil <youngjin.gil@samsung.com>
Signed-off-by: Sunmin Jeong <s_min.jeong@samsung.com>
Reviewed-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/segment.c

index c9b0ef7302bebfa89e75de21cd92359f15aaca4a..e9e8b9bb3ce9b6c0f7b4407a3749b235aed3f3a2 100644 (file)
@@ -192,6 +192,9 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
        if (!f2fs_is_atomic_file(inode))
                return;
 
+       if (clean)
+               truncate_inode_pages_final(inode->i_mapping);
+
        release_atomic_write_cnt(inode);
        clear_inode_flag(inode, FI_ATOMIC_COMMITTED);
        clear_inode_flag(inode, FI_ATOMIC_REPLACE);
@@ -201,7 +204,6 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
        F2FS_I(inode)->atomic_write_task = NULL;
 
        if (clean) {
-               truncate_inode_pages_final(inode->i_mapping);
                f2fs_i_size_write(inode, fi->original_i_size);
                fi->original_i_size = 0;
        }