diff options
author | Chao Yu <yuchao0@huawei.com> | 2021-03-31 17:46:48 +0800 |
---|---|---|
committer | Chao Yu <yuchao0@huawei.com> | 2021-04-03 00:57:43 +0800 |
commit | b03f6152e147ea188a45501b8de7eed54b997dc9 (patch) | |
tree | e6dc64648563642586a55eb459c57728fda2c427 | |
parent | 268b38f2676d79b974693876c82c982b85eb371e (diff) | |
download | linux-dax-wip.tar.gz |
f2fs: dax optionsdax-wip
Signed-off-by: Chao Yu <yuchao0@huawei.com>
-rw-r--r-- | fs/f2fs/f2fs.h | 25 | ||||
-rw-r--r-- | fs/f2fs/file.c | 77 | ||||
-rw-r--r-- | fs/f2fs/inode.c | 12 | ||||
-rw-r--r-- | fs/f2fs/namei.c | 2 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 3 | ||||
-rw-r--r-- | fs/f2fs/super.c | 69 | ||||
-rw-r--r-- | fs/f2fs/verity.c | 2 |
7 files changed, 173 insertions, 17 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 1fc7839a7f925..6ca41b222107a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -152,6 +152,9 @@ struct f2fs_mount_info { unsigned char compress_ext_cnt; /* extension count */ int compress_mode; /* compression mode */ unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ + + /* For dax */ + int dax_mode; /* dax mode */ }; #define F2FS_FEATURE_ENCRYPT 0x0001 @@ -1292,6 +1295,19 @@ enum { */ }; +enum { + DAX_MODE_NONE, /* no dax option */ + DAX_MODE_ALWAYS, /* always set S_DAX ignore FS_XFLAG_DAX */ + DAX_MODE_NEVER, /* never set S_DAX, ignore FS_XFLAG_DAX */ + DAX_MODE_INODE, /* follow FS_XFLAG_DAX" and is the default */ + DAX_MODE_LAGECY, + /* + * is a legacy option which is an alias for "dax=always". + * This may be removed in the future so "-o dax=always" is + * the preferred method for specifying this behavior. + */ +}; + /* * this value is set in page as a private data which indicate that * the page is atomically written, and it is in inmem_pages list. @@ -2655,11 +2671,13 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) #define F2FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define F2FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ #define F2FS_CASEFOLD_FL 0x40000000 /* Casefolded file */ +#define F2FS_DAX_FL 0x80000000 /* Dax file */ /* Flags that should be inherited by new inodes from their parent. */ #define F2FS_FL_INHERITED (F2FS_SYNC_FL | F2FS_NODUMP_FL | F2FS_NOATIME_FL | \ F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL | \ - F2FS_CASEFOLD_FL | F2FS_COMPR_FL | F2FS_NOCOMP_FL) + F2FS_CASEFOLD_FL | F2FS_COMPR_FL | F2FS_NOCOMP_FL | \ + F2FS_DAX_FL) /* Flags that are appropriate for regular files (all but dir-specific ones). */ #define F2FS_REG_FLMASK (~(F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL | \ @@ -3210,6 +3228,7 @@ int f2fs_getattr(struct user_namespace *mnt_userns, const struct path *path, int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, struct iattr *attr); int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end); +bool f2fs_should_enable_dax(struct inode *inode); void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count); int f2fs_precache_extents(struct inode *inode); long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -3220,7 +3239,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc); /* * inode.c */ -void f2fs_set_inode_flags(struct inode *inode); +void f2fs_set_inode_flags(struct inode *inode, bool init); bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page); void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page); struct inode *f2fs_iget(struct super_block *sb, unsigned long ino); @@ -3923,7 +3942,7 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) { #ifdef CONFIG_FS_ENCRYPTION file_set_encrypt(inode); - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); #endif } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index bb87b9fafb790..6993a2a7a3b03 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1900,6 +1900,61 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) return 0; } +static bool dax_mutually_exclusive(struct inode *inode) +{ + if (file_is_encrypt(inode)) + return false; + if (file_is_verity(inode)) + return false; + if (f2fs_has_inline_data(inode)) + return true; + return false; +} + +static bool dax_compatible(struct inode *inode, unsigned int iflags) +{ + if (!(iflags & F2FS_DAX_FL)) + return true; + if (dax_mutually_exclusive(inode)) + return false; + if (f2fs_verity_in_progress(inode)) + return false; + return true; +} + +bool f2fs_should_enable_dax(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_NEVER) + return false; + if (!S_ISREG(inode->i_mode)) + return false; + if (dax_mutually_exclusive(inode)) + return false; + if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_ALWAYS || + F2FS_OPTION(sbi).dax_mode == DAX_MODE_LAGECY) + return true; + + return F2FS_I(inode)->i_flags & F2FS_DAX_FL; +} + +static void dax_dontcache(struct inode *inode, unsigned int oldflags, + unsigned int iflags) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + if (S_ISDIR(inode->i_mode)) + return; + + if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_ALWAYS || + F2FS_OPTION(sbi).dax_mode == DAX_MODE_NEVER) + return; + + if ((oldflags ^ iflags) & F2FS_DAX_FL) + d_mark_dontcache(inode); +} + static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) { struct f2fs_inode_info *fi = F2FS_I(inode); @@ -1946,6 +2001,11 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) return -EINVAL; } + if (!dax_compatible(inode, iflags)) + return -EOPNOTSUPP; + + dax_dontcache(inode, masked_flags, iflags); + fi->i_flags = iflags | (fi->i_flags & ~mask); f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) && (fi->i_flags & F2FS_NOCOMP_FL)); @@ -1956,7 +2016,7 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) clear_inode_flag(inode, FI_PROJ_INHERIT); inode->i_ctime = current_time(inode); - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); f2fs_mark_inode_dirty_sync(inode, true); return 0; } @@ -1985,6 +2045,7 @@ static const struct { { F2FS_DIRSYNC_FL, FS_DIRSYNC_FL }, { F2FS_PROJINHERIT_FL, FS_PROJINHERIT_FL }, { F2FS_CASEFOLD_FL, FS_CASEFOLD_FL }, + { F2FS_DAX_FL, FS_DAX_FL }, }; #define F2FS_GETTABLE_FS_FL ( \ @@ -2002,7 +2063,8 @@ static const struct { FS_INLINE_DATA_FL | \ FS_NOCOW_FL | \ FS_VERITY_FL | \ - FS_CASEFOLD_FL) + FS_CASEFOLD_FL | \ + FS_DAX_FL) #define F2FS_SETTABLE_FS_FL ( \ FS_COMPR_FL | \ @@ -2014,7 +2076,8 @@ static const struct { FS_NOCOMP_FL | \ FS_DIRSYNC_FL | \ FS_PROJINHERIT_FL | \ - FS_CASEFOLD_FL) + FS_CASEFOLD_FL | \ + FS_DAX_FL) /* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */ static inline u32 f2fs_iflags_to_fsflags(u32 iflags) @@ -3220,6 +3283,7 @@ static const struct { { F2FS_NODUMP_FL, FS_XFLAG_NODUMP }, { F2FS_NOATIME_FL, FS_XFLAG_NOATIME }, { F2FS_PROJINHERIT_FL, FS_XFLAG_PROJINHERIT }, + { F2FS_DAX_FL, FS_XFLAG_DAX }, }; #define F2FS_SUPPORTED_XFLAGS ( \ @@ -3228,7 +3292,8 @@ static const struct { FS_XFLAG_APPEND | \ FS_XFLAG_NODUMP | \ FS_XFLAG_NOATIME | \ - FS_XFLAG_PROJINHERIT) + FS_XFLAG_PROJINHERIT | \ + FS_XFLAG_DAX) /* Convert f2fs on-disk i_flags to FS_IOC_FS{GET,SET}XATTR flags */ static inline u32 f2fs_iflags_to_xflags(u32 iflags) @@ -3670,7 +3735,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) goto out; F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); @@ -3871,7 +3936,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) if (ret >= 0) { F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 5d2253d53f179..cd3e8c7fdb3ab 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -29,11 +29,13 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) mark_inode_dirty_sync(inode); } -void f2fs_set_inode_flags(struct inode *inode) +void f2fs_set_inode_flags(struct inode *inode, bool init) { unsigned int flags = F2FS_I(inode)->i_flags; unsigned int new_fl = 0; + WARN_ON_ONCE(init && IS_DAX(inode)); + if (flags & F2FS_SYNC_FL) new_fl |= S_SYNC; if (flags & F2FS_APPEND_FL) @@ -44,6 +46,10 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |= S_NOATIME; if (flags & F2FS_DIRSYNC_FL) new_fl |= S_DIRSYNC; + if (IS_DAX(inode)) + new_fl |= S_DAX; + if (init && f2fs_should_enable_dax(inode)) + new_fl |= S_DAX; if (file_is_encrypt(inode)) new_fl |= S_ENCRYPTED; if (file_is_verity(inode)) @@ -52,7 +58,7 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |= S_CASEFOLD; inode_set_flags(inode, new_fl, S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC| - S_ENCRYPTED|S_VERITY|S_CASEFOLD); + S_ENCRYPTED|S_VERITY|S_CASEFOLD|S_DAX); } static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) @@ -528,7 +534,7 @@ make_now: ret = -EIO; goto bad_inode; } - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, true); unlock_new_inode(inode); trace_f2fs_iget(inode); return inode; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 17bd072a5d393..90c87228dfc27 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -129,7 +129,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) set_compress_context(inode); } - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, true); trace_f2fs_new_inode(inode, 0); return inode; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index da75d5d52f0ac..cd880f7355e31 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -319,7 +319,8 @@ static int recover_inode(struct inode *inode, struct page *page) F2FS_I(inode)->i_advise = raw->i_advise; F2FS_I(inode)->i_flags = le32_to_cpu(raw->i_flags); - f2fs_set_inode_flags(inode); + inode->i_flags &= ~S_DAX; + f2fs_set_inode_flags(inode, true); F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = le16_to_cpu(raw->i_gc_failures); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5863344be60fd..15e01ab6351ea 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -156,6 +156,8 @@ enum { Opt_atgc, Opt_gc_merge, Opt_nogc_merge, + Opt_dax, + Opt_dax_mode, Opt_err, }; @@ -230,6 +232,8 @@ static match_table_t f2fs_tokens = { {Opt_atgc, "atgc"}, {Opt_gc_merge, "gc_merge"}, {Opt_nogc_merge, "nogc_merge"}, + {Opt_dax, "dax"}, + {Opt_dax_mode, "dax=%s"}, {Opt_err, NULL}, }; @@ -1086,6 +1090,35 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) case Opt_nogc_merge: clear_opt(sbi, GC_MERGE); break; + case Opt_dax: +#ifdef CONFIG_FS_DAX + F2FS_OPTION(sbi).dax_mode = DAX_MODE_LAGECY; + break; +#else + f2fs_info(sbi, "dax option not supported"); + break; +#endif + case Opt_dax_mode: +#ifdef CONFIG_FS_DAX + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (!strcmp(name, "always")) { + F2FS_OPTION(sbi).dax_mode = DAX_MODE_ALWAYS; + } else if (!strcmp(name, "never")) { + F2FS_OPTION(sbi).dax_mode = DAX_MODE_NEVER; + } else if (!strcmp(name, "inode")) { + F2FS_OPTION(sbi).dax_mode = DAX_MODE_INODE; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; +#else + f2fs_info(sbi, "dax option not supported"); + break; +#endif default: f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", p); @@ -1159,6 +1192,26 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) return -EINVAL; } + if (test_opt(sbi, DISABLE_CHECKPOINT) && + test_opt(sbi, MERGE_CHECKPOINT)) { + f2fs_err(sbi, "checkpoint=merge cannot be used with checkpoint=disable\n"); + return -EINVAL; + } + +#ifdef CONFIG_FS_DAX + if (F2FS_OPTION(sbi).dax_mode != DAX_MODE_NONE) { + if (test_opt(sbi, INLINE_DATA)) { + f2fs_err(sbi, "Dax can not be enabled with inline_data " + "mountoption\n"); + return -EINVAL; + } + if (!bdev_dax_supported(sb->s_bdev, F2FS_BLKSIZE)) { + f2fs_warn(sbi, "DAX unsupported by block device. Turning off DAX."); + F2FS_OPTION(sbi).dax_mode = DAX_MODE_NONE; + } + } +#endif + /* Not pass down write hints if the number of active logs is lesser * than NR_CURSEG_PERSIST_TYPE. */ @@ -1818,6 +1871,17 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) if (test_opt(sbi, ATGC)) seq_puts(seq, ",atgc"); + +#ifdef CONFIG_FS_DAX + if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_ALWAYS) + seq_printf(seq, ",dax=%s", "always"); + else if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_NEVER) + seq_printf(seq, ",dax=%s", "never"); + else if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_INODE) + seq_printf(seq, ",dax=%s", "inode"); + else if (F2FS_OPTION(sbi).dax_mode == DAX_MODE_LAGECY) + seq_puts(seq, ",dax"); +#endif return 0; } @@ -1836,6 +1900,7 @@ static void default_options(struct f2fs_sb_info *sbi) F2FS_OPTION(sbi).compress_ext_cnt = 0; F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS; F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; + F2FS_OPTION(sbi).dax_mode = DAX_MODE_NONE; sbi->sb->s_flags &= ~SB_INLINECRYPT; @@ -2479,7 +2544,7 @@ static int f2fs_quota_on(struct super_block *sb, int type, int format_id, inode_lock(inode); F2FS_I(inode)->i_flags |= F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); inode_unlock(inode); f2fs_mark_inode_dirty_sync(inode, false); @@ -2504,7 +2569,7 @@ static int __f2fs_quota_off(struct super_block *sb, int type) inode_lock(inode); F2FS_I(inode)->i_flags &= ~(F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL); - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); inode_unlock(inode); f2fs_mark_inode_dirty_sync(inode, false); out_put: diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index 15ba36926fad7..784b14dc81935 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -192,7 +192,7 @@ static int f2fs_end_enable_verity(struct file *filp, const void *desc, /* Finally, set the verity inode flag. */ file_set_verity(inode); - f2fs_set_inode_flags(inode); + f2fs_set_inode_flags(inode, false); f2fs_mark_inode_dirty_sync(inode, true); clear_inode_flag(inode, FI_VERITY_IN_PROGRESS); |