f2fs: fix to avoid race in between atomic write and background GC
authorChao Yu <yuchao0@huawei.com>
Tue, 27 Feb 2018 14:45:24 +0000 (22:45 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 12 Mar 2018 23:05:55 +0000 (08:05 +0900)
Sqlite user Background GC
- move_data_block
  : move page #1
 - f2fs_is_atomic_file
- f2fs_ioc_start_atomic_write
- f2fs_ioc_commit_atomic_write
 - commit_inmem_pages
   : commit page #1 & set node #2 dirty
 - f2fs_submit_page_write
  - f2fs_update_data_blkaddr
   - set_page_dirty
     : set node #2 dirty
 - f2fs_do_sync_file
  - fsync_node_pages
   : commit node #1 & node #2, then sudden power-cut

In a race case, we may check FI_ATOMIC_FILE flag before starting atomic
write flow, then we will commit meta data before data with reversed
order, after a sudden pow-cut, database transaction will be inconsistent.

So we'd better to exclude gc/atomic_write to each other by using lock
instead of flag checking.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/file.c

index c0a80987e88e40fb02fb9459ddcf827843f98d90..6a202e5a6386d2780df5a282fe3a3e6984583f64 100644 (file)
@@ -1715,6 +1715,8 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
 
        inode_lock(inode);
 
+       down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
        if (f2fs_is_volatile_file(inode))
                goto err_out;
 
@@ -1733,6 +1735,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
                ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
        }
 err_out:
+       up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
        inode_unlock(inode);
        mnt_drop_write_file(filp);
        return ret;