NFSv4 mandates a change attribute to avoid problems with timestamp granularity, which Linux implements using the i_version counter. This is particularly important when the underlying filesystem is fast. BTW introduce a new mount option to enable the iversion functionality, and disabling it by default. Signed-off-by: Wenbo Hong <wenbo.hong@xxxxxxxx> Signed-off-by: Yangtao Li <frank.li@xxxxxxxx> --- Documentation/filesystems/f2fs.rst | 2 ++ fs/f2fs/f2fs.h | 1 + fs/f2fs/inode.c | 2 ++ fs/f2fs/super.c | 17 +++++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index d32c6209685d..eac23bc0bb92 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -367,6 +367,8 @@ errors=%s Specify f2fs behavior on critical errors. This supports modes: pending node write drop keep N/A pending meta write keep keep N/A ====================== =============== =============== ======== +iversion Enable the feature of updating the inode I_version field. +noiversion Disable the feature of updating the inode I_version field. ======================== ============================================================ Debugfs Entries diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9043cedfa12b..68fd2ef35104 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -28,6 +28,7 @@ #include <linux/fscrypt.h> #include <linux/fsverity.h> +#include <linux/iversion.h> struct pagevec; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 560bfcad1af2..b741eea7e724 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -32,6 +32,8 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) if (f2fs_inode_dirtied(inode, sync)) return; + if (IS_I_VERSION(inode)) + inode_inc_iversion(inode); mark_inode_dirty_sync(inode); } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 033af907c3b1..adae708e869c 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -180,6 +180,8 @@ enum { Opt_memory_mode, Opt_age_extent_cache, Opt_errors, + Opt_iversion, + Opt_noiversion, Opt_err, }; @@ -260,6 +262,8 @@ static match_table_t f2fs_tokens = { {Opt_memory_mode, "memory=%s"}, {Opt_age_extent_cache, "age_extent_cache"}, {Opt_errors, "errors=%s"}, + {Opt_iversion, "iversion"}, + {Opt_noiversion, "noiversion"}, {Opt_err, NULL}, }; @@ -1334,6 +1338,12 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) } kfree(name); break; + case Opt_iversion: + sb->s_flags |= SB_I_VERSION; + break; + case Opt_noiversion: + sb->s_flags &= ~SB_I_VERSION; + break; default: f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", p); @@ -2152,6 +2162,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC) seq_printf(seq, ",errors=%s", "panic"); + if (sbi->sb->s_flags & SB_I_VERSION) + seq_puts(seq, ",iversion"); + else + seq_puts(seq, ",noiversion"); + return 0; } @@ -2196,6 +2211,7 @@ static void default_options(struct f2fs_sb_info *sbi, bool remount) F2FS_OPTION(sbi).errors = MOUNT_ERRORS_CONTINUE; sbi->sb->s_flags &= ~SB_INLINECRYPT; + sbi->sb->s_flags &= ~SB_I_VERSION; set_opt(sbi, INLINE_XATTR); set_opt(sbi, INLINE_DATA); @@ -2574,6 +2590,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) limit_reserve_root(sbi); adjust_unusable_cap_perc(sbi); *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); + *flags = (*flags & ~SB_I_VERSION) | (sb->s_flags & SB_I_VERSION); return 0; restore_checkpoint: if (need_enable_checkpoint) { -- 2.39.0