f2fs: add an ioctl to disable GC for specific file
Jaegeuk Kim
maintainerPATCH 1/1 f2fs: add an ioctl to disable GC for specific file
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 85 insertions(+)
fs/f2fs/f2fs.h +17 -0
@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;
@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +52 -0
70 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +1 -0
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ struct f2fs_inode {__le16 i_mode;/* file mode */
Signature · 1 line
2.15.0.531.g2ccb3012c9-goog
Jaegeuk Kim
maintainerChange log from v1:
- fix bug in error handling of ioctl
Quoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001
From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific file
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)
fs/f2fs/f2fs.h +17 -0
@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;
@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +54 -0
72 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +1 -0
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ struct f2fs_inode {__le16 i_mode;/* file mode */
Signature · 1 line
2.15.0.531.g2ccb3012c9-goog
Hi Jaegeuk,
Quoted 10 lines · Jaegeuk Kim
Change log from v1:
- fix bug in error handling of ioctlQuoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific fileThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
Could you add some description about in which scenario userspace application can use this ioctl, otherwise than android, other developers can get hint about the usage of this interface, maybe later it can be used more wildly. ;)
Thanks,
Quoted 249 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)fs/f2fs/f2fs.h +17
-0@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_dontmove_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_current_depth for normal file as a risk signal. */ +if (inc) +f2fs_i_depth_write (inode, fi->i_current_depth +1 ); + +if (fi->i_current_depth > sbi->gc_dontmove) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_current_depth); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_dontmove (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_dontmove_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_DONTMOVE ); + ret =F2FS_I (inode)->i_current_depth; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_DONTMOVE : +return f2fs_ioc_set_dontmove (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_DONTMOVE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +1
-0@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ struct f2fs_inode {__le16 i_mode;/* file mode */
Jaegeuk Kim
maintainerQuoted 11 lines · Chao Yu
Hi Jaegeuk,
Quoted 8 lines · Jaegeuk Kim
Change log from v1:
- fix bug in error handling of ioctlQuoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific file
Quoted 6 lines
Quoted 2 lines
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
Could you add some description about in which scenario userspace application can use this ioctl, otherwise than android, other developers can get hint about the usage of this interface, maybe later it can be used more wildly. ;)
The usecase would be somewhat hacky tho, it looks like 1) building a block map through fibmap, 2) storing the map in another partition, 3) using the map to overwrite data contents directly by low-level tools. In that case, we have to keep its block locations.
Thanks,
Quoted 252 lines
Thanks,
Quoted 249 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)fs/f2fs/f2fs.h +17
-0@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_dontmove_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_current_depth for normal file as a risk signal. */ +if (inc) +f2fs_i_depth_write (inode, fi->i_current_depth +1 ); + +if (fi->i_current_depth > sbi->gc_dontmove) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_current_depth); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_dontmove (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_dontmove_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_DONTMOVE ); + ret =F2FS_I (inode)->i_current_depth; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_DONTMOVE : +return f2fs_ioc_set_dontmove (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_DONTMOVE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +1
-0@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ struct f2fs_inode {__le16 i_mode;/* file mode */
Quoted 15 lines · Jaegeuk Kim
Quoted 14 lines · Chao Yu
Hi Jaegeuk,
Quoted 10 lines · Jaegeuk Kim
Change log from v1:
- fix bug in error handling of ioctlQuoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific fileThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
Quoted 8 lines
Quoted 3 lines
Could you add some description about in which scenario userspace application can use this ioctl, otherwise than android, other developers can get hint about the usage of this interface, maybe later it can be used more wildly. ;)
The usecase would be somewhat hacky tho, it looks like 1) building a block map through fibmap, 2) storing the map in another partition, 3) using the map to overwrite data contents directly by low-level tools. In that case, we have to keep its block locations.
That's so hacky, it will be better to add simple description in comment log. ;)
Quoted 102 lines
Thanks,
Quoted 99 lines
Thanks,
Quoted 96 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)fs/f2fs/f2fs.h +17
-0@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +0
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; }
Quoted 1 line
Quoted 1 line
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2669
Quoted 1 line
fs/f2fs/file.c +1
-0+int f2fs_dontmove_control (struct inode *inode,bool inc)
What's the purpose here? If GC tries to move block belong to unremovable inode, we don't allow to set other inode as unremovable one?
Quoted 9 lines
Quoted 9 lines
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2678
Quoted 9 lines
fs/f2fs/file.c +9
-0+{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_current_depth for normal file as a risk signal. */ +if (inc) +f2fs_i_depth_write (inode, fi->i_current_depth +1 ); + +if (fi->i_current_depth > sbi->gc_dontmove) {
If we want to persist per-inode metadata, what about adding new field in inode layout to store such metadata?
Thanks,
Quoted 146 lines
Quoted 140 lines
Quoted 140 lines
fs/f2fs/file.c +44
-0+f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_current_depth); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_dontmove (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_dontmove_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_DONTMOVE ); + ret =F2FS_I (inode)->i_current_depth; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_DONTMOVE : +return f2fs_ioc_set_dontmove (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_DONTMOVE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +1
-0@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ Quoted 3 lines
include/linux/f2fs_fs.h struct f2fs_extent { · line 218
Quoted 3 lines
include/linux/f2fs_fs.h +0
-0struct f2fs_inode {__le16 i_mode;/* file mode */ .
Jaegeuk Kim
maintainerQuoted 20 lines · Chao Yu
Quoted 19 lines · Jaegeuk Kim
Quoted 17 lines · Chao Yu
Hi Jaegeuk,
Quoted 10 lines · Jaegeuk Kim
Change log from v1:
- fix bug in error handling of ioctlQuoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific fileThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
Could you add some description about in which scenario userspace application can use this ioctl, otherwise than android, other developers can get hint about the usage of this interface, maybe later it can be used more wildly. ;)
Quoted 6 lines
Quoted 4 lines
The usecase would be somewhat hacky tho, it looks like 1) building a block map through fibmap, 2) storing the map in another partition, 3) using the map to overwrite data contents directly by low-level tools. In that case, we have to keep its block locations.
That's so hacky, it will be better to add simple description in comment log. ;)
Actually, I don't want to add this kind of hacky example. :P
Quoted 95 lines
Quoted 95 lines
Quoted 95 lines
Quoted 95 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)fs/f2fs/f2fs.h +17
-0@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +0
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; }
Quoted 4 lines
Quoted 1 line
Quoted 1 line
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2669
Quoted 1 line
fs/f2fs/file.c +1
-0+int f2fs_dontmove_control (struct inode *inode,bool inc)What's the purpose here? If GC tries to move block belong to unremovable inode, we don't allow to set other inode as unremovable one?
I just wanted to avoid infinite loop to move this during foreground GC case.
Quoted 13 lines
Quoted 10 lines
Quoted 10 lines
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2678
Quoted 10 lines
fs/f2fs/file.c +9
-0+{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_current_depth for normal file as a risk signal. */ +if (inc) +f2fs_i_depth_write (inode, fi->i_current_depth +1 ); + +if (fi->i_current_depth > sbi->gc_dontmove) {If we want to persist per-inode metadata, what about adding new field in inode layout to store such metadata?
I thought that this would not be such the important field which makes us extend inode fields.
Thanks,
Quoted 149 lines
Thanks,
Quoted 146 lines
Quoted 140 lines
Quoted 140 lines
fs/f2fs/file.c +44
-0+f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_current_depth); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_dontmove (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_dontmove_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_DONTMOVE ); + ret =F2FS_I (inode)->i_current_depth; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_DONTMOVE : +return f2fs_ioc_set_dontmove (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_DONTMOVE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +1
-0@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ Quoted 3 lines
include/linux/f2fs_fs.h struct f2fs_extent { · line 218
Quoted 3 lines
include/linux/f2fs_fs.h +0
-0struct f2fs_inode {__le16 i_mode;/* file mode */ .
Quoted 21 lines · Jaegeuk Kim
Quoted 20 lines · Chao Yu
Quoted 19 lines · Jaegeuk Kim
Quoted 17 lines · Chao Yu
Hi Jaegeuk,
Quoted 10 lines · Jaegeuk Kim
Change log from v1:
- fix bug in error handling of ioctlQuoted 1 line
From
b905e03d8aad7d25ecaf9bde05411a68d3d2460eMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Thu, 7 Dec 2017 16:25:39 -0800
Subject: [PATCH] f2fs: add an ioctl to disable GC for specific fileThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map.
Could you add some description about in which scenario userspace application can use this ioctl, otherwise than android, other developers can get hint about the usage of this interface, maybe later it can be used more wildly. ;)
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
The usecase would be somewhat hacky tho, it looks like 1) building a block map through fibmap, 2) storing the map in another partition, 3) using the map to overwrite data contents directly by low-level tools. In that case, we have to keep its block locations.
That's so hacky, it will be better to add simple description in comment log. ;)
Actually, I don't want to add this kind of hacky example. :P
No a big deal, anyway, I've know your purpose. ;)
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/f2fs.h | 17 ++++++++++++++++ fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 1 + 6 files changed, 87 insertions(+)fs/f2fs/f2fs.h +17
-0@@ -375,6 +375,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_SET_DONTMOVE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -1129,6 +1131,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for dontmove gc trials */ +u64 gc_dontmove; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2104,6 +2109,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_DONTMOVE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2117,6 +2123,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_DONTMOVE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2225,6 +2232,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_DONTMOVE ) +set_bit (FI_DONTMOVE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2243,6 +2252,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_DONTMOVE )) + ri->i_inline |=F2FS_DONTMOVE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2288,6 +2299,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_dontmove_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_DONTMOVE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2503,6 +2519,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_dontmove_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +0
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; }
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2669
Quoted 1 line
fs/f2fs/file.c +1
-0+int f2fs_dontmove_control (struct inode *inode,bool inc)What's the purpose here? If GC tries to move block belong to unremovable inode, we don't allow to set other inode as unremovable one?
I just wanted to avoid infinite loop to move this during foreground GC case.
If so, do we need to account unremovable block number in each segment, and if the count in candidate section is non-null, we just skip selecting the section as victim of GC?
BTW, all caller passed false value in @inc, do you intend to call dontmove_control(, true) in f2fs_gc?
Quoted 15 lines
Quoted 14 lines
Quoted 11 lines
Quoted 11 lines
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2678
Quoted 11 lines
fs/f2fs/file.c +9
-0+{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_current_depth for normal file as a risk signal. */ +if (inc) +f2fs_i_depth_write (inode, fi->i_current_depth +1 ); + +if (fi->i_current_depth > sbi->gc_dontmove) {If we want to persist per-inode metadata, what about adding new field in inode layout to store such metadata?
Quoted 2 lines
I thought that this would not be such the important field which makes us extend inode fields.
OK, how about changing this field in inode layout as below:
union {
__le32 i_current_depth; /* only for directory depth */
__le16 i_gc_failed_count; /*
* # of gc failed to move unremovable
* block, for regular only. */
}
Thanks,
Quoted 155 lines
Thanks,
Quoted 149 lines
Thanks,
Quoted 146 lines
Quoted 140 lines
Quoted 140 lines
fs/f2fs/file.c +44
-0+f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_current_depth); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_dontmove (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_dontmove_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_DONTMOVE ); + ret =F2FS_I (inode)->i_current_depth; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_DONTMOVE : +return f2fs_ioc_set_dontmove (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_DONTMOVE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +f2fs_dontmove_control (inode, false); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_dontmove_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_dontmove_control (inode, false); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_dontmove =DEF_GC_FAILED_DONTMOVE ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_DONTMOVE 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -300,6 +300,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_dontmove, gc_dontmove);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -348,6 +349,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_dontmove), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +1
-0@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_DONTMOVE 0x40/* file should not be move */ Quoted 3 lines
include/linux/f2fs_fs.h struct f2fs_extent { · line 218
Quoted 3 lines
include/linux/f2fs_fs.h +0
-0struct f2fs_inode {__le16 i_mode;/* file mode */ .
.
Jaegeuk Kim
maintainerThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
---
Change log from v2:
- change the naming from dontmove to pin_file
- do in-place-update for pinned files
- use union for i_current_depth with i_gc_failures
- pass increasing i_gc_failures
fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 +++++++++++++++++++++++++- fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++++- 7 files changed, 107 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -0
@@ -1394,6 +1394,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))
fs/f2fs/f2fs.h +28 -1
@@ -376,6 +376,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_PIN_FILE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;
@@ -586,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */
@@ -1130,6 +1135,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2119,6 +2127,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2132,6 +2141,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2212,6 +2222,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;
@@ -2240,6 +2257,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2258,6 +2277,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2303,6 +2324,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2518,6 +2544,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +54 -0
72 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -303,6 +303,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -351,6 +352,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +8 -1
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */
@@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Signature · 1 line
2.15.0.531.g2ccb3012c9-goog
Quoted 3 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
One question, we may encounter out-of-space during foreground GC if there is too many data blocks of pinned files as they are removable.
Do we need to record all segments which contain block of pinned file? and then trigger foreground GC more early by adjust threshold in has_not_enough_free_secs.
Thanks,
Quoted 311 lines
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- change the naming from dontmove topin_file
- do in-place-update for pinned files
- use union fori_current_depthwithi_gc_failures
- pass increasingi_gc_failuresfs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 +++++++++++++++++++++++++- fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++++- 7 files changed, 107 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1394,6 +1394,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +28
-1@@ -376,6 +376,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_PIN_FILE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -586,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1130,6 +1135,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2119,6 +2127,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2132,6 +2141,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2212,6 +2222,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2240,6 +2257,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2258,6 +2277,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2303,6 +2324,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2518,6 +2544,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_pin_file (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_PIN_FILE : +return f2fs_ioc_pin_file (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -303,6 +303,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -351,6 +352,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +8
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Jaegeuk Kim
maintainerQuoted 11 lines · Chao Yu
Quoted 3 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
One question, we may encounter out-of-space during foreground GC if there is too many data blocks of pinned files as they are removable.
Do we need to record all segments which contain block of pinned file? and then trigger foreground GC more early by adjust threshold in
has_not_enough_free_secs.
This should be used only when application knows how this works. If not, I wanted to just unset the flag as much as possible, as foreground GCs have been done for pinned file too frequently. I expect the usecase must be quite unusual with just small number of files in short period likewise atomic files.
Thanks,
Quoted 314 lines
Thanks,
Quoted 311 lines
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- change the naming from dontmove topin_file
- do in-place-update for pinned files
- use union fori_current_depthwithi_gc_failures
- pass increasingi_gc_failuresfs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 +++++++++++++++++++++++++- fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++++- 7 files changed, 107 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1394,6 +1394,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +28
-1@@ -376,6 +376,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_PIN_FILE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -586,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1130,6 +1135,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2119,6 +2127,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2132,6 +2141,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2212,6 +2222,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2240,6 +2257,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2258,6 +2277,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2303,6 +2324,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2518,6 +2544,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_pin_file (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_PIN_FILE : +return f2fs_ioc_pin_file (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -303,6 +303,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -351,6 +352,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +8
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Quoted 9 lines · Jaegeuk Kim
Quoted 8 lines · Chao Yu
Quoted 3 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
One question, we may encounter out-of-space during foreground GC if there is too many data blocks of pinned files as they are removable.
Quoted 6 lines
Quoted 3 lines
Do we need to record all segments which contain block of pinned file? and then trigger foreground GC more early by adjust threshold in
has_not_enough_free_secs.This should be used only when application knows how this works. If not, I wanted to just unset the flag as much as possible, as foreground GCs have been done for
Well, how can we unset that flag? do we need an extra ioctl interface like F2FS_IOC_UNPIN_FILE? so that user can keep its data in unpinned file by calling that interface. Or user can only drop the flag by unlinking pinned file?
Thanks,
Quoted 322 lines
pinned file too frequently. I expect the usecase must be quite unusual with just small number of files in short period likewise atomic files.
Thanks,
Quoted 306 lines
Thanks,
Quoted 303 lines
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- change the naming from dontmove topin_file
- do in-place-update for pinned files
- use union fori_current_depthwithi_gc_failures
- pass increasingi_gc_failuresfs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 +++++++++++++++++++++++++- fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++++- 7 files changed, 107 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1394,6 +1394,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +28
-1@@ -376,6 +376,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_PIN_FILE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -586,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1130,6 +1135,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2119,6 +2127,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2132,6 +2141,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2212,6 +2222,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2240,6 +2257,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2258,6 +2277,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2303,6 +2324,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2518,6 +2544,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_pin_file (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_PIN_FILE : +return f2fs_ioc_pin_file (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -303,6 +303,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -351,6 +352,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +4
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* Quoted 8 lines
include/linux/f2fs_fs.h struct f2fs_inode { · line 242
Quoted 8 lines
include/linux/f2fs_fs.h +4
-0+* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */ .
Jaegeuk Kim
maintainerQuoted 14 lines · Chao Yu
Quoted 13 lines · Jaegeuk Kim
Quoted 11 lines · Chao Yu
Quoted 3 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
One question, we may encounter out-of-space during foreground GC if there is too many data blocks of pinned files as they are removable.
Do we need to record all segments which contain block of pinned file? and then trigger foreground GC more early by adjust threshold in
has_not_enough_free_secs.
Quoted 7 lines
Quoted 2 lines
This should be used only when application knows how this works. If not, I wanted to just unset the flag as much as possible, as foreground GCs have been done for
Well, how can we unset that flag? do we need an extra ioctl interface like
F2FS_IOC_UNPIN_FILE? so that user can keep its data in unpinned file by calling that interface. Or user can only drop the flag by unlinking pinned file?
I've modified ioctl to get this done.
Thanks,
Quoted 325 lines
Thanks,
Quoted 322 lines
pinned file too frequently. I expect the usecase must be quite unusual with just small number of files in short period likewise atomic files.
Thanks,
Quoted 306 lines
Thanks,
Quoted 303 lines
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- change the naming from dontmove topin_file
- do in-place-update for pinned files
- use union fori_current_depthwithi_gc_failures
- pass increasingi_gc_failuresfs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 +++++++++++++++++++++++++- fs/f2fs/file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 ++++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++++- 7 files changed, 107 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1394,6 +1394,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +28
-1@@ -376,6 +376,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR +#define F2FS_IOC_PIN_FILE _IO(F2FS_IOCTL_MAGIC, 13) +struct f2fs_gc_range {u32 sync;u64 start;@@ -586,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1130,6 +1135,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2119,6 +2127,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2132,6 +2141,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2212,6 +2222,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2240,6 +2257,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2258,6 +2277,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2303,6 +2324,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2518,6 +2544,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +54
-0@@ -2666,6 +2666,57 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_pin_file (struct file *filp) +{ +struct inode *inode =file_inode (filp); +int ret; + +if (!inode_owner_or_capable (inode)) +return -EACCES ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ; + +inode_lock (inode); + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode); +return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2716,6 +2767,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_PIN_FILE : +return f2fs_ioc_pin_file (filp);default :return -ENOTTY ; }@@ -2791,6 +2844,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -303,6 +303,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -351,6 +352,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +4
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* Quoted 8 lines
include/linux/f2fs_fs.h struct f2fs_inode { · line 242
Quoted 8 lines
include/linux/f2fs_fs.h +4
-0+* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */ .
Jaegeuk Kim
maintainerThis patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
---
Change log from v2:
- modify ioctl to allow users unpin the file
fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 28 +++++++++++++++++++++- fs/f2fs/file.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++- 7 files changed, 116 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -0
@@ -1395,6 +1395,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))
fs/f2fs/f2fs.h +27 -1
@@ -350,6 +350,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ struct f2fs_gc_range)#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -587,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */
@@ -1133,6 +1137,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2124,6 +2131,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2137,6 +2145,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2217,6 +2226,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;
@@ -2245,6 +2261,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2263,6 +2281,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2308,6 +2328,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2523,6 +2548,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +64 -0
82 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -301,6 +301,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -349,6 +350,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +8 -1
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */
@@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Signature · 1 line
2.15.0.531.g2ccb3012c9-goog
Chao Yu
Reviewed-byQuoted 167 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- modify ioctl to allow users unpin the filefs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 28 +++++++++++++++++++++- fs/f2fs/file.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++- 7 files changed, 116 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1395,6 +1395,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +27
-1@@ -350,6 +350,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ struct f2fs_gc_range)#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY@@ -587,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1133,6 +1137,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2124,6 +2131,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2137,6 +2145,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2217,6 +2226,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2245,6 +2261,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2263,6 +2281,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2308,6 +2328,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2523,6 +2548,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +25
-0@@ -2669,6 +2669,67 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_pin_file (struct file *filp,unsigned long arg) +{ +struct inode *inode =file_inode (filp); +__u32 pin; +int ret =0 ; + +if (!inode_owner_or_capable (inode))
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2706
Quoted 10 lines
fs/f2fs/file.c +10
-0+return -EACCES ; + +if (get_user (pin, (__u32 __user *)arg)) +return -EFAULT ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ;
mnt_want_write_file(filp)?
Quoted 13 lines
fs/f2fs/file.c +13
-0+ +inode_lock (inode); + +if (!pin) { +clear_inode_flag (inode,FI_PIN_FILE ); +F2FS_I (inode)->i_gc_failures =0 ; + goto done; + } + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + }
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2729
Quoted 10 lines
fs/f2fs/file.c +10
-0+ ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; + +set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +done: +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode);
mnt_drop_write_file(filp)?
Other part looks good to me. ;)
Thanks,
Quoted 120 lines
fs/f2fs/file.c +6
-0+return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2719,6 +2780,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_PIN_FILE : +return f2fs_ioc_set_pin_file (filp, arg);default :return -ENOTTY ; }@@ -2794,6 +2857,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -301,6 +301,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -349,6 +350,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +8
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Jaegeuk Kim
maintainerQuoted 198 lines · Chao Yu
Quoted 167 lines · Jaegeuk Kim
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
Signed-off-by Jaegeuk Kim <[email protected]>---
Change log from v2:
- modify ioctl to allow users unpin the filefs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 28 +++++++++++++++++++++- fs/f2fs/file.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 ++++++- 7 files changed, 116 insertions(+), 2 deletions(-)fs/f2fs/data.c +2
-0@@ -1395,6 +1395,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))fs/f2fs/f2fs.h +27
-1@@ -350,6 +350,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ struct f2fs_gc_range)#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY@@ -587,7 +588,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */ @@ -1133,6 +1137,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;@@ -2124,6 +2131,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,@@ -2137,6 +2145,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }@@ -2217,6 +2226,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;@@ -2245,6 +2261,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)@@ -2263,6 +2281,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)@@ -2308,6 +2328,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );@@ -2523,6 +2548,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c fs/f2fs/file.c +25
-0@@ -2669,6 +2669,67 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)return 0 ; } +int f2fs_pin_file_control (struct inode *inode,bool inc) +{ +struct f2fs_inode_info *fi =F2FS_I (inode); +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); + +/* Use i_gc_failures for normal file as a risk signal. */ +if (inc) +f2fs_i_gc_failures_write (inode, fi->i_gc_failures +1 ); + +if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { +f2fs_msg (sbi->sb,KERN_WARNING , +"%s: Enable GC = ino %lx after %x GC trials\n" , + __func__, inode->i_ino, fi->i_gc_failures); +return -EAGAIN ; + } +return 0 ; +} + +static int f2fs_ioc_set_pin_file (struct file *filp,unsigned long arg) +{ +struct inode *inode =file_inode (filp); +__u32 pin; +int ret =0 ; + +if (!inode_owner_or_capable (inode))fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2706
Quoted 10 lines
fs/f2fs/file.c +10
-0+return -EACCES ; + +if (get_user (pin, (__u32 __user *)arg)) +return -EFAULT ; + +if (!S_ISREG (inode->i_mode)) +return -EINVAL ; + +if (f2fs_readonly (F2FS_I_SB (inode)->sb)) +return -EROFS ;
mnt_want_write_file(filp)?Quoted 17 lines
fs/f2fs/file.c +17
-0+ +inode_lock (inode); + +if (!pin) { +clear_inode_flag (inode,FI_PIN_FILE ); +F2FS_I (inode)->i_gc_failures =0 ; + goto done; + } + +if (f2fs_pin_file_control (inode, false)) { + ret = -EAGAIN ; + goto out; + } + ret =f2fs_convert_inline_inode (inode); +if (ret) + goto out; +
Quoted 8 lines
fs/f2fs/file.c static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) · line 2729
Quoted 6 lines
fs/f2fs/file.c +6
-0+set_inode_flag (inode,FI_PIN_FILE ); + ret =F2FS_I (inode)->i_gc_failures; +done: +f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); +out: +inode_unlock (inode);
mnt_drop_write_file(filp)?
Done. Thanks. :)
Quoted 127 lines
Other part looks good to me. ;)
Reviewed-by Chao Yu <[email protected]>Thanks,
Quoted 120 lines
fs/f2fs/file.c +6
-0+return ret; +} +long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {if (unlikely (f2fs_cp_error (F2FS_I_SB (file_inode (filp)))))@@ -2719,6 +2780,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)return f2fs_ioc_fsgetxattr (filp, arg);case F2FS_IOC_FSSETXATTR :return f2fs_ioc_fssetxattr (filp, arg); +case F2FS_IOC_SET_PIN_FILE : +return f2fs_ioc_set_pin_file (filp, arg);default :return -ENOTTY ; }@@ -2794,6 +2857,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)case F2FS_IOC_GET_FEATURES :case F2FS_IOC_FSGETXATTR :case F2FS_IOC_FSSETXATTR : +case F2FS_IOC_SET_PIN_FILE :break ;default :return -ENOIOCTLCMD ;fs/f2fs/gc.c +11
-0@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )fs/f2fs/gc.h +2
-0@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */ fs/f2fs/sysfs.c +2
-0@@ -301,6 +301,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);@@ -349,6 +350,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),include/linux/f2fs_fs.h +8
-1@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */ @@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
---
Change log from v3:
- add F2FS_IOC_GET_PIN_FILE
- fix to reset i_gc_failures as 1, not 0
fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 ++++++++++++++++- fs/f2fs/file.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 +++++- 7 files changed, 135 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -0
@@ -1479,6 +1479,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))
fs/f2fs/f2fs.h +28 -1
@@ -356,6 +356,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ struct f2fs_gc_range)#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32) +#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -593,7 +595,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */
@@ -1142,6 +1147,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2144,6 +2152,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2158,6 +2167,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2238,6 +2248,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;
@@ -2266,6 +2283,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2284,6 +2303,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2329,6 +2350,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2543,6 +2569,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +82 -0
100 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 1024 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -301,6 +301,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -349,6 +350,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +8 -1
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */
@@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Signature · 6 lines
2.15.0.531.g2ccb3012c9-goog ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
This patch gives a flag to disable GC on given file, which would be useful, when user wants to keep its block map. It also conducts in-place-update for dontmove file.
---
Change log from v1:
- unset pin_file, if # of trials exceeds a threshold
- increase the threshold to 2048
fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 29 ++++++++++++++++- fs/f2fs/file.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/gc.c | 11 +++++++ fs/f2fs/gc.h | 2 ++ fs/f2fs/sysfs.c | 2 ++ include/linux/f2fs_fs.h | 9 +++++- 7 files changed, 136 insertions(+), 2 deletions(-)
fs/f2fs/data.c +2 -0
@@ -1479,6 +1479,8 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio) {struct inode *inode = fio->page->mapping->host; +if (f2fs_is_pinned_file (inode)) +return true;if (S_ISDIR (inode->i_mode) ||f2fs_is_atomic_file (inode))return false;if (is_cold_data (fio->page))
fs/f2fs/f2fs.h +28 -1
@@ -356,6 +356,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ struct f2fs_gc_range)#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32) +#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -593,7 +595,10 @@ struct f2fs_inode_info {unsigned long i_flags;/* keep an inode flags for ioctl */ unsigned char i_advise;/* use to give file attribute hints */ unsigned char i_dir_level;/* use for dentry level for large dir */ -unsigned int i_current_depth;/* use only in directory structure */ +union { +unsigned int i_current_depth;/* only for directory depth */ +unsigned short i_gc_failures;/* only for regular file */ + };unsigned int i_pino;/* parent inode number */ umode_t i_acl_mode;/* keep file acl mode temporarily */
@@ -1142,6 +1147,9 @@ struct f2fs_sb_info {/* threshold for converting bg victims for fg */ u64 fggc_threshold; +/* threshold for gc trials on pinned files */ +u64 gc_pin_file_threshold; +/* maximum # of trials to find a victim segment for SSR and GC */ unsigned int max_victim_search;
@@ -2141,6 +2149,7 @@ enum {FI_HOT_DATA ,/* indicate file is hot */ FI_EXTRA_ATTR ,/* indicate file has extra attribute */ FI_PROJ_INHERIT ,/* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ }; static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2155,6 +2164,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : +case FI_PIN_FILE :f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -2235,6 +2245,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)f2fs_mark_inode_dirty_sync (inode, true); } +static inline void f2fs_i_gc_failures_write (struct inode *inode, +unsigned int count) +{ +F2FS_I (inode)->i_gc_failures = count; +f2fs_mark_inode_dirty_sync (inode, true); +} +static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid;
@@ -2263,6 +2280,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)set_bit (FI_INLINE_DOTS , &fi->flags);if (ri->i_inline &F2FS_EXTRA_ATTR )set_bit (FI_EXTRA_ATTR , &fi->flags); +if (ri->i_inline &F2FS_PIN_FILE ) +set_bit (FI_PIN_FILE , &fi->flags); }static inline void set_raw_inline (struct inode *inode,struct f2fs_inode *ri)
@@ -2281,6 +2300,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |=F2FS_INLINE_DOTS ;if (is_inode_flag_set (inode,FI_EXTRA_ATTR )) ri->i_inline |=F2FS_EXTRA_ATTR ; +if (is_inode_flag_set (inode,FI_PIN_FILE )) + ri->i_inline |=F2FS_PIN_FILE ; }static inline int f2fs_has_extra_attr (struct inode *inode)
@@ -2326,6 +2347,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)return is_inode_flag_set (inode,FI_INLINE_DOTS ); } +static inline bool f2fs_is_pinned_file (struct inode *inode) +{ +return is_inode_flag_set (inode,FI_PIN_FILE ); +} +static inline bool f2fs_is_atomic_file (struct inode *inode) {return is_inode_flag_set (inode,FI_ATOMIC_FILE );
@@ -2540,6 +2566,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);void truncate_data_blocks_range (struct dnode_of_data *dn,int count);long f2fs_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long f2fs_compat_ioctl (struct file *file,unsigned int cmd,unsigned long arg); +int f2fs_pin_file_control (struct inode *inode,bool inc);/* * inode.c
fs/f2fs/file.c +83 -0
101 lines not on this page · raw message
fs/f2fs/gc.c +11 -0
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +f2fs_pin_file_control (inode, true); + goto out; + } +set_new_dnode (&dn, inode,NULL ,NULL ,0 ); err =get_dnode_of_data (&dn, bidx,LOOKUP_NODE );if (err)
@@ -720,6 +725,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,if (f2fs_is_atomic_file (inode)) goto out; +if (f2fs_is_pinned_file (inode)) { +if (gc_type ==FG_GC ) +f2fs_pin_file_control (inode, true); + goto out; + }if (gc_type ==BG_GC ) {if (PageWriteback (page))
@@ -1091,6 +1101,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) sbi->fggc_threshold =div64_u64 ((main_count - ovp_count) *BLKS_PER_SEC (sbi), (main_count - resv_count)); + sbi->gc_pin_file_threshold =DEF_GC_FAILED_PINNED_FILES ;/* give warm/cold data area from slower device */ if (sbi->s_ndevs && sbi->segs_per_sec ==1 )
fs/f2fs/gc.h +2 -0
@@ -20,6 +20,8 @@#define LIMIT_INVALID_BLOCK 40/* percentage over total user space */ #define LIMIT_FREE_BLOCK 40/* percentage over invalid + free space */ +#define DEF_GC_FAILED_PINNED_FILES 2048 +/* Search max. number of dirty segments to select a victim segment */ #define DEF_MAX_VICTIM_SEARCH 4096/* covers 8GB */
fs/f2fs/sysfs.c +2 -0
@@ -301,6 +301,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, idle_interval, interval_time[REQ_TIME ]);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, iostat_enable, iostat_enable);F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, readdir_ra, readdir_ra); +F2FS_RW_ATTR (F2FS_SBI , f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);#ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR (FAULT_INFO_RATE , f2fs_fault_info, inject_rate, inject_rate);F2FS_RW_ATTR (FAULT_INFO_TYPE , f2fs_fault_info, inject_type, inject_type);
@@ -349,6 +350,7 @@ static struct attribute *f2fs_attrs[] = {ATTR_LIST (idle_interval),ATTR_LIST (iostat_enable),ATTR_LIST (readdir_ra), +ATTR_LIST (gc_pin_file_thresh), #ifdef CONFIG_F2FS_FAULT_INJECTIONATTR_LIST (inject_rate), ATTR_LIST(inject_type),
include/linux/f2fs_fs.h +8 -1
@@ -212,6 +212,7 @@ struct f2fs_extent {#define F2FS_DATA_EXIST 0x08/* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10/* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20/* file having extra attribute */ +#define F2FS_PIN_FILE 0x40/* file should not be gced */ struct f2fs_inode {__le16 i_mode;/* file mode */
@@ -229,7 +230,13 @@ struct f2fs_inode {__le32 i_ctime_nsec;/* change time in nano scale */ __le32 i_mtime_nsec;/* modification time in nano scale */ __le32 i_generation;/* file version (for NFS) */ -__le32 i_current_depth;/* only for directory depth */ +union { +__le32 i_current_depth;/* only for directory depth */ +__le16 i_gc_failures;/* +* # of gc failures on pinned file. +* only for regular files. +*/ + };__le32 i_xattr_nid;/* nid to save xattr */ __le32 i_flags;/* file attributes */ __le32 i_pino;/* parent inode number */
Signature · 1 line
2.15.0.531.g2ccb3012c9-goog