Re: [PATCH] f2fs: introduce hot_data_age_threshold and warm_data_age_threshold mount opt
From: Jaegeuk Kim
Date: Tue Jan 03 2023 - 21:26:24 EST
On 12/06, Yangtao Li wrote:
> This patch supports parsing these two parameters from mount opt,
> so that we don't have to dynamically modify the parameters through
> the sysfs node after the system starts.
It seems sysfs would be enough?
>
> Signed-off-by: Yangtao Li <frank.li@xxxxxxxx>
> ---
> Documentation/filesystems/f2fs.rst | 6 +++++
> fs/f2fs/debug.c | 3 ++-
> fs/f2fs/extent_cache.c | 14 +++++++----
> fs/f2fs/f2fs.h | 14 +++++++----
> fs/f2fs/segment.c | 8 ++++---
> fs/f2fs/super.c | 38 +++++++++++++++++++++++++++++-
> fs/f2fs/sysfs.c | 16 +++++++++----
> 7 files changed, 81 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
> index 220f3e0d3f55..12a04d7cd634 100644
> --- a/Documentation/filesystems/f2fs.rst
> +++ b/Documentation/filesystems/f2fs.rst
> @@ -351,6 +351,12 @@ age_extent_cache Enable an age extent cache based on rb-tree. It records
> data block update frequency of the extent per inode, in
> order to provide better temperature hints for data block
> allocation.
> +hot_data_age_threshold=%u When age_extent_cache is on, it controls the age
> + threshold to indicate the data blocks as hot. By default it was
> + initialized as 262144 blocks(equals to 1GB).
> +warm_data_age_threshold=%u When age_extent_cache is on, it controls the age
> + threshold to indicate the data blocks as warm. By default it was
> + initialized as 2621440 blocks(equals to 10GB).
> ======================== ============================================================
>
> Debugfs Entries
> diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
> index 8f1ef742551f..5bf9c1ed7a2f 100644
> --- a/fs/f2fs/debug.c
> +++ b/fs/f2fs/debug.c
> @@ -62,6 +62,7 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi)
> #ifdef CONFIG_DEBUG_FS
> static void update_general_status(struct f2fs_sb_info *sbi)
> {
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> struct f2fs_stat_info *si = F2FS_STAT(sbi);
> struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
> int i;
> @@ -89,7 +90,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
> si->hit_total[EX_READ] += si->hit_largest;
>
> /* block age extent_cache only */
> - si->allocated_data_blocks = atomic64_read(&sbi->allocated_data_blocks);
> + si->allocated_data_blocks = atomic64_read(&fai->allocated_data_blocks);
>
> /* validation check of the segment numbers */
> si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
> diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
> index 2fc675c45606..601659714aa9 100644
> --- a/fs/f2fs/extent_cache.c
> +++ b/fs/f2fs/extent_cache.c
> @@ -883,9 +883,10 @@ static unsigned long long __calculate_block_age(unsigned long long new,
> static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
> {
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> loff_t f_size = i_size_read(inode);
> unsigned long long cur_blocks =
> - atomic64_read(&sbi->allocated_data_blocks);
> + atomic64_read(&fai->allocated_data_blocks);
>
> /*
> * When I/O is not aligned to a PAGE_SIZE, update will happen to the last
> @@ -1216,13 +1217,18 @@ static void __init_extent_tree_info(struct extent_tree_info *eti)
>
> void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi)
> {
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> +
> __init_extent_tree_info(&sbi->extent_tree[EX_READ]);
> __init_extent_tree_info(&sbi->extent_tree[EX_BLOCK_AGE]);
>
> /* initialize for block age extents */
> - atomic64_set(&sbi->allocated_data_blocks, 0);
> - sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
> - sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
> + atomic64_set(&fai->allocated_data_blocks, 0);
> +
> + if (!fai->hot_data_age_threshold)
> + fai->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
> + if (!fai->warm_data_age_threshold)
> + fai->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
> }
>
> int __init f2fs_create_extent_cache(void)
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index eb71edcf70de..32a0bf2977bc 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -64,6 +64,12 @@ enum {
> FAULT_MAX,
> };
>
> +struct f2fs_age_extent_info {
> + atomic64_t allocated_data_blocks; /* for block age extent_cache */
> + unsigned int hot_data_age_threshold; /* The threshold used for hot data seperation*/
> + unsigned int warm_data_age_threshold; /* The threshold used for warm data seperation*/
> +};
> +
> #ifdef CONFIG_F2FS_FAULT_INJECTION
> #define F2FS_ALL_FAULT_TYPE ((1 << FAULT_MAX) - 1)
>
> @@ -148,6 +154,7 @@ struct f2fs_mount_info {
> kgid_t s_resgid; /* reserved blocks for gid */
> int active_logs; /* # of active logs */
> int inline_xattr_size; /* inline xattr size */
> + struct f2fs_age_extent_info age_info; /* For block age extent */
> #ifdef CONFIG_F2FS_FAULT_INJECTION
> struct f2fs_fault_info fault_info; /* For fault injection */
> #endif
> @@ -173,6 +180,8 @@ struct f2fs_mount_info {
> * unusable when disabling checkpoint
> */
>
> + /* For block age extent_cache */
> +
> /* For compression */
> unsigned char compress_algorithm; /* algorithm type */
> unsigned char compress_log_size; /* cluster log size */
> @@ -1674,11 +1683,6 @@ struct f2fs_sb_info {
>
> /* for extent tree cache */
> struct extent_tree_info extent_tree[NR_EXTENT_CACHES];
> - atomic64_t allocated_data_blocks; /* for block age extent_cache */
> -
> - /* The threshold used for hot and warm data seperation*/
> - unsigned int hot_data_age_threshold;
> - unsigned int warm_data_age_threshold;
>
> /* basic filesystem units */
> unsigned int log_sectors_per_block; /* log2 sectors per block */
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index dee712f7225f..c9b779fd7041 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -3159,14 +3159,15 @@ static int __get_segment_type_4(struct f2fs_io_info *fio)
> static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
> {
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> struct extent_info ei;
>
> if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
> if (!ei.age)
> return NO_CHECK_TYPE;
> - if (ei.age <= sbi->hot_data_age_threshold)
> + if (ei.age <= fai->hot_data_age_threshold)
> return CURSEG_HOT_DATA;
> - if (ei.age <= sbi->warm_data_age_threshold)
> + if (ei.age <= fai->warm_data_age_threshold)
> return CURSEG_WARM_DATA;
> return CURSEG_COLD_DATA;
> }
> @@ -3242,6 +3243,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
> struct f2fs_summary *sum, int type,
> struct f2fs_io_info *fio)
> {
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> struct sit_info *sit_i = SIT_I(sbi);
> struct curseg_info *curseg = CURSEG_I(sbi, type);
> unsigned long long old_mtime;
> @@ -3316,7 +3318,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
> locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
>
> if (IS_DATASEG(type))
> - atomic64_inc(&sbi->allocated_data_blocks);
> + atomic64_inc(&fai->allocated_data_blocks);
>
> up_write(&sit_i->sentry_lock);
>
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 5bdab376b852..feea2006b070 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -164,6 +164,8 @@ enum {
> Opt_discard_unit,
> Opt_memory_mode,
> Opt_age_extent_cache,
> + Opt_hot_data_age_threshold,
> + Opt_warm_data_age_threshold,
> Opt_err,
> };
>
> @@ -243,6 +245,8 @@ static match_table_t f2fs_tokens = {
> {Opt_discard_unit, "discard_unit=%s"},
> {Opt_memory_mode, "memory=%s"},
> {Opt_age_extent_cache, "age_extent_cache"},
> + {Opt_hot_data_age_threshold, "hot_data_age_threshold=%u"},
> + {Opt_warm_data_age_threshold, "warm_data_age_threshold=%u"},
> {Opt_err, NULL},
> };
>
> @@ -658,6 +662,7 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
> static int parse_options(struct super_block *sb, char *options, bool is_remount)
> {
> struct f2fs_sb_info *sbi = F2FS_SB(sb);
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> substring_t args[MAX_OPT_ARGS];
> #ifdef CONFIG_F2FS_FS_COMPRESSION
> unsigned char (*ext)[F2FS_EXTENSION_LEN];
> @@ -1262,6 +1267,32 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
> case Opt_age_extent_cache:
> set_opt(sbi, AGE_EXTENT_CACHE);
> break;
> + case Opt_hot_data_age_threshold:
> + if (!test_opt(sbi, AGE_EXTENT_CACHE)) {
> + f2fs_info(sbi, "age extent options not enabled");
> + break;
> + }
> + if (args->from && match_int(args, &arg))
> + return -EINVAL;
> + if (arg == 0 || arg > DEF_HOT_DATA_AGE_THRESHOLD) {
> + f2fs_err(sbi, "hot data age threshold is out of range");
> + return -EINVAL;
> + }
> + fai->hot_data_age_threshold = arg;
> + break;
> + case Opt_warm_data_age_threshold:
> + if (!test_opt(sbi, AGE_EXTENT_CACHE)) {
> + f2fs_info(sbi, "age extent options not enabled");
> + break;
> + }
> + if (args->from && match_int(args, &arg))
> + return -EINVAL;
> + if (arg == 0 || arg > DEF_WARM_DATA_AGE_THRESHOLD) {
> + f2fs_err(sbi, "warm data age threshold is out of range");
> + return -EINVAL;
> + }
> + fai->warm_data_age_threshold = arg;
> + break;
> default:
> f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
> p);
> @@ -1963,8 +1994,13 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
> seq_puts(seq, ",read_extent_cache");
> else
> seq_puts(seq, ",no_read_extent_cache");
> - if (test_opt(sbi, AGE_EXTENT_CACHE))
> + if (test_opt(sbi, AGE_EXTENT_CACHE)) {
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> +
> seq_puts(seq, ",age_extent_cache");
> + seq_printf(seq, ",hot_data_age_threshold=%u", fai->hot_data_age_threshold);
> + seq_printf(seq, ",warm_data_age_threshold=%u", fai->warm_data_age_threshold);
> + }
> if (test_opt(sbi, DATA_FLUSH))
> seq_puts(seq, ",data_flush");
>
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 2ab215110596..5b8e08aff0a6 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -36,6 +36,7 @@ enum {
> FAULT_INFO_RATE, /* struct f2fs_fault_info */
> FAULT_INFO_TYPE, /* struct f2fs_fault_info */
> #endif
> + AGE_EXTENT_INFO, /* struct f2fs_age_extent_info */
> RESERVED_BLOCKS, /* struct f2fs_sb_info */
> CPRC_INFO, /* struct ckpt_req_control */
> ATGC_INFO, /* struct atgc_management */
> @@ -81,6 +82,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
> struct_type == FAULT_INFO_TYPE)
> return (unsigned char *)&F2FS_OPTION(sbi).fault_info;
> #endif
> + else if (struct_type == AGE_EXTENT_INFO)
> + return (unsigned char *)&F2FS_OPTION(sbi).age_info;
> #ifdef CONFIG_F2FS_STAT_FS
> else if (struct_type == STAT_INFO)
> return (unsigned char *)F2FS_STAT(sbi);
> @@ -669,7 +672,9 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
> }
>
> if (!strcmp(a->attr.name, "hot_data_age_threshold")) {
> - if (t == 0 || t >= sbi->warm_data_age_threshold)
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> +
> + if (t == 0 || t >= fai->warm_data_age_threshold)
> return -EINVAL;
> if (t == *ui)
> return count;
> @@ -678,7 +683,9 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
> }
>
> if (!strcmp(a->attr.name, "warm_data_age_threshold")) {
> - if (t == 0 || t <= sbi->hot_data_age_threshold)
> + struct f2fs_age_extent_info *fai = &F2FS_OPTION(sbi).age_info;
> +
> + if (t == 0 || t <= fai->hot_data_age_threshold)
> return -EINVAL;
> if (t == *ui)
> return count;
> @@ -942,8 +949,9 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, committed_atomic_block, committed_atomic_bl
> F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, revoked_atomic_block, revoked_atomic_block);
>
> /* For block age extent cache */
> -F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, hot_data_age_threshold, hot_data_age_threshold);
> -F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, warm_data_age_threshold, warm_data_age_threshold);
> +F2FS_RW_ATTR(AGE_EXTENT_INFO, f2fs_age_extent_info, hot_data_age_threshold, hot_data_age_threshold);
> +F2FS_RW_ATTR(AGE_EXTENT_INFO, f2fs_age_extent_info, warm_data_age_threshold,
> + warm_data_age_threshold);
>
> #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
> static struct attribute *f2fs_attrs[] = {
> --
> 2.25.1