[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20221206063616.68522-1-frank.li@vivo.com>
Date: Tue, 6 Dec 2022 14:36:16 +0800
From: Yangtao Li <frank.li@...o.com>
To: jaegeuk@...nel.org, chao@...nel.org
Cc: linux-f2fs-devel@...ts.sourceforge.net,
linux-kernel@...r.kernel.org, qixiaoyu1@...omi.com,
xiongping1@...omi.com, Yangtao Li <frank.li@...o.com>
Subject: [PATCH] f2fs: introduce hot_data_age_threshold and warm_data_age_threshold mount opt
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.
Signed-off-by: Yangtao Li <frank.li@...o.com>
---
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
Powered by blists - more mailing lists