f2fs: introduce mount option for fsync mode
authorJunling Zheng <zhengjunling@huawei.com>
Wed, 7 Mar 2018 04:07:49 +0000 (12:07 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Sun, 8 Apr 2018 11:13:28 +0000 (04:13 -0700)
Commit "0a007b97aad6"(f2fs: recover directory operations by fsync)
fixed xfstest generic/342 case, but it also increased the written
data and caused the performance degradation. In most cases, there's
no need to do so heavy fsync actually.

So we introduce new mount option "fsync_mode={posix,strict}" to
control the policy of fsync. "fsync_mode=posix" is set by default,
and means that f2fs uses a light fsync, which follows POSIX semantics.
And "fsync_mode=strict" means that it's a heavy fsync, which behaves
in line with xfs, ext4 and btrfs, where generic/342 will pass, but
the performance will regress.

Signed-off-by: Junling Zheng <zhengjunling@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Documentation/filesystems/f2fs.txt
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/namei.c
fs/f2fs/super.c

index bd26d37a85112c78c530b7e3a02d674608d6d261..20bcb582b57fbb541ddc98e648faee2741a81176 100644 (file)
@@ -182,6 +182,13 @@ whint_mode=%s          Control which write hints are passed down to block
                        passes down hints with its policy.
 alloc_mode=%s          Adjust block allocation policy, which supports "reuse"
                        and "default".
+fsync_mode=%s          Control the policy of fsync. Currently supports "posix"
+                       and "strict". In "posix" mode, which is default, fsync
+                       will follow POSIX semantics and does a light operation
+                       to improve the filesystem performance. In "strict" mode,
+                       fsync will be heavy and behaves in line with xfs, ext4
+                       and btrfs, where xfstest generic/342 will pass, but the
+                       performance will regress.
 
 ================================================================================
 DEBUGFS ENTRIES
index 797eb05cb53864ddd858f52f29db655830996a00..87c51709bc48a68ef1c0585701ffdd8f4eb8cddf 100644 (file)
@@ -704,7 +704,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
 
        f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
 
-       add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+       if (F2FS_I_SB(dir)->fsync_mode == FSYNC_MODE_STRICT)
+               add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
 
        if (f2fs_has_inline_dentry(dir))
                return f2fs_delete_inline_entry(dentry, page, dir, inode);
index 0e47fe93c7187b656d1bb3bd952d7f5246ac7d6e..3c79b3565cb3ea6bb75b1f5ccb2a245c4f1a0d31 100644 (file)
@@ -1052,6 +1052,11 @@ enum {
        ALLOC_MODE_REUSE,       /* reuse segments as much as possible */
 };
 
+enum fsync_mode {
+       FSYNC_MODE_POSIX,       /* fsync follows posix semantics */
+       FSYNC_MODE_STRICT,      /* fsync behaves in line with ext4 */
+};
+
 struct f2fs_sb_info {
        struct super_block *sb;                 /* pointer to VFS super block */
        struct proc_dir_entry *s_proc;          /* proc entry */
@@ -1241,6 +1246,9 @@ struct f2fs_sb_info {
 
        /* segment allocation policy */
        int alloc_mode;
+
+       /* fsync policy */
+       int fsync_mode;
 };
 
 #ifdef CONFIG_F2FS_FAULT_INJECTION
index d1658bdfb82eaf67dc0bdeadfe7fd6ae694ef1cb..fdcdcb2adc27c4e83ee9f43347caebfa831bb6d0 100644 (file)
@@ -165,7 +165,8 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
                cp_reason = CP_FASTBOOT_MODE;
        else if (sbi->active_logs == 2)
                cp_reason = CP_SPEC_LOG_NUM;
-       else if (need_dentry_mark(sbi, inode->i_ino) &&
+       else if (sbi->fsync_mode == FSYNC_MODE_STRICT &&
+               need_dentry_mark(sbi, inode->i_ino) &&
                exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
                cp_reason = CP_RECOVER_DIR;
 
index 78ea0156f027a1acf99366bffabd785f31d85bb7..e9bb3a3a8b0a643e6afde90813e8c36786d1a122 100644 (file)
@@ -970,7 +970,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        f2fs_put_page(old_dir_page, 0);
                f2fs_i_links_write(old_dir, false);
        }
-       add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+       if (sbi->fsync_mode == FSYNC_MODE_STRICT)
+               add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
 
        f2fs_unlock_op(sbi);
 
@@ -1120,8 +1121,10 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
        f2fs_mark_inode_dirty_sync(new_dir, false);
 
-       add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
-       add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+       if (sbi->fsync_mode == FSYNC_MODE_STRICT) {
+               add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+               add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+       }
 
        f2fs_unlock_op(sbi);
 
index a77bb9bae9ea4c7755a3ff59542610a7cb88c53b..b6318078c28716e3540d8c49b8ab39b90c73d505 100644 (file)
@@ -131,6 +131,7 @@ enum {
        Opt_jqfmt_vfsv1,
        Opt_whint,
        Opt_alloc,
+       Opt_fsync,
        Opt_err,
 };
 
@@ -186,6 +187,7 @@ static match_table_t f2fs_tokens = {
        {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
        {Opt_whint, "whint_mode=%s"},
        {Opt_alloc, "alloc_mode=%s"},
+       {Opt_fsync, "fsync_mode=%s"},
        {Opt_err, NULL},
 };
 
@@ -719,6 +721,22 @@ static int parse_options(struct super_block *sb, char *options)
                        }
                        kfree(name);
                        break;
+               case Opt_fsync:
+                       name = match_strdup(&args[0]);
+                       if (!name)
+                               return -ENOMEM;
+                       if (strlen(name) == 5 &&
+                                       !strncmp(name, "posix", 5)) {
+                               sbi->fsync_mode = FSYNC_MODE_POSIX;
+                       } else if (strlen(name) == 6 &&
+                                       !strncmp(name, "strict", 6)) {
+                               sbi->fsync_mode = FSYNC_MODE_STRICT;
+                       } else {
+                               kfree(name);
+                               return -EINVAL;
+                       }
+                       kfree(name);
+                       break;
                default:
                        f2fs_msg(sb, KERN_ERR,
                                "Unrecognized mount option \"%s\" or missing value",
@@ -1287,6 +1305,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_printf(seq, ",alloc_mode=%s", "default");
        else if (sbi->alloc_mode == ALLOC_MODE_REUSE)
                seq_printf(seq, ",alloc_mode=%s", "reuse");
+
+       if (sbi->fsync_mode == FSYNC_MODE_POSIX)
+               seq_printf(seq, ",fsync_mode=%s", "posix");
+       else if (sbi->fsync_mode == FSYNC_MODE_STRICT)
+               seq_printf(seq, ",fsync_mode=%s", "strict");
        return 0;
 }
 
@@ -1297,6 +1320,7 @@ static void default_options(struct f2fs_sb_info *sbi)
        sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
        sbi->whint_mode = WHINT_MODE_OFF;
        sbi->alloc_mode = ALLOC_MODE_DEFAULT;
+       sbi->fsync_mode = FSYNC_MODE_POSIX;
        sbi->readdir_ra = 1;
 
        set_opt(sbi, BG_GC);
@@ -1340,6 +1364,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
        int old_whint_mode = sbi->whint_mode;
        int old_alloc_mode = sbi->alloc_mode;
+       int old_fsync_mode = sbi->fsync_mode;
        int old_inline_xattr_size = sbi->inline_xattr_size;
        block_t old_root_reserved_blocks = sbi->root_reserved_blocks;
        kuid_t old_resuid = sbi->s_resuid;
@@ -1500,6 +1525,7 @@ restore_opts:
        sbi->root_reserved_blocks = old_root_reserved_blocks;
        sbi->inline_xattr_size = old_inline_xattr_size;
        sbi->alloc_mode = old_alloc_mode;
+       sbi->fsync_mode = old_fsync_mode;
        sbi->whint_mode = old_whint_mode;
        sbi->mount_opt = org_mount_opt;
        sbi->active_logs = active_logs;