[5/5] f2fs: implement data block seperation with block update frequency

Message ID 20221128085859.5295-6-qixiaoyu1@xiaomi.com
State New
Headers
Series Support enhanced hot/cold data separation for f2fs |

Commit Message

qixiaoyu1 Nov. 28, 2022, 8:58 a.m. UTC
  Signed-off-by: qixiaoyu1 <qixiaoyu1@xiaomi.com>
Signed-off-by: xiongping1 <xiongping1@xiaomi.com>
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 14 ++++++++++++
 fs/f2fs/block_age.c                     | 29 +++++++++++++++++++++++++
 fs/f2fs/f2fs.h                          |  4 ++++
 fs/f2fs/segment.c                       |  9 ++++++++
 fs/f2fs/sysfs.c                         | 28 ++++++++++++++++++++++++
 include/trace/events/f2fs.h             |  2 +-
 6 files changed, 85 insertions(+), 1 deletion(-)
  

Patch

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index 483639fb727b..34952666b2fe 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -634,3 +634,17 @@  Date:		July 2022
 Contact:	"Daeho Jeong" <daehojeong@google.com>
 Description:	Show the accumulated total revoked atomic write block count after boot.
 		If you write "0" here, you can initialize to "0".
+
+What:		/sys/fs/f2fs/<disk>/hot_data_age_threshold
+Date:		November 2022
+Contact:	"Ping Xiong" <xiongping1@xiaomi.com>
+Description:	When DATA SEPARATION 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).
+
+What:		/sys/fs/f2fs/<disk>/warm_data_age_threshold
+Date:		November 2022
+Contact:	"Ping Xiong" <xiongping1@xiaomi.com>
+Description:	When DATA SEPARATION 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).
diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
index 488461b3f4bf..d0b578544df7 100644
--- a/fs/f2fs/block_age.c
+++ b/fs/f2fs/block_age.c
@@ -17,6 +17,13 @@ 
 #define LAST_AGE_WEIGHT		30
 #define SAME_AGE_REGION		1024
 
+/*
+ * Define data block with age less than 1GB as hot data
+ * define data block with age less than 10GB but more than 1GB as warm data
+ */
+#define DEF_HOT_DATA_AGE_THRESHOLD	262144
+#define DEF_WARM_DATA_AGE_THRESHOLD	2621440
+
 static struct kmem_cache *age_extent_tree_slab;
 static struct kmem_cache *age_extent_node_slab;
 
@@ -29,6 +36,9 @@  static inline void f2fs_inc_data_block_alloc(struct f2fs_sb_info *sbi)
 static void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
 {
 	atomic64_set(&sbi->total_data_alloc, 0);
+
+	sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
+	sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
 }
 
 static inline bool f2fs_may_age_extent_tree(struct inode *inode)
@@ -697,6 +707,25 @@  unsigned long f2fs_count_age_extent_cache(struct f2fs_sb_info *sbi)
 				atomic_read(&sbi->total_age_ext_node);
 }
 
+int f2fs_get_data_segment_type(struct inode *inode, pgoff_t pgofs)
+{
+	struct age_extent_info ei;
+	struct f2fs_sb_info *sbi =  F2FS_I_SB(inode);
+
+	if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
+		if (ei.age != 0) {
+			if (ei.age <= sbi->hot_data_age_threshold)
+				return CURSEG_HOT_DATA;
+			else if (ei.age <= sbi->warm_data_age_threshold)
+				return CURSEG_WARM_DATA;
+			else
+				return CURSEG_COLD_DATA;
+		}
+	}
+
+	return NO_CHECK_TYPE;
+}
+
 void f2fs_destroy_age_extent_cache(void)
 {
 	kmem_cache_destroy(age_extent_node_slab);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 23516498b6d0..50f6f21b23bf 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1854,6 +1854,9 @@  struct f2fs_sb_info {
 
 #ifdef CONFIG_F2FS_FS_DATA_SEPARATION
 	atomic64_t total_data_alloc;
+	/* The threshold used for hot and warm data seperation*/
+	unsigned int hot_data_age_threshold;
+	unsigned int warm_data_age_threshold;
 #endif
 
 	/* Reference to checksum algorithm driver via cryptoapi */
@@ -4241,6 +4244,7 @@  void f2fs_update_age_extent_cache(struct inode *inode, pgoff_t fofs,
 void f2fs_update_data_block_age(struct dnode_of_data *dn);
 void f2fs_truncate_age_extent_cache(struct inode *inode, pgoff_t fofs,
 					unsigned int len);
+int f2fs_get_data_segment_type(struct inode *inode, pgoff_t pgofs);
 int __init f2fs_create_age_extent_cache(void);
 void f2fs_destroy_age_extent_cache(void);
 #endif
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index d4c338f332fa..2fa5b22119ac 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3163,6 +3163,9 @@  static int __get_segment_type_6(struct f2fs_io_info *fio)
 	if (fio->type == DATA) {
 		struct inode *inode = fio->page->mapping->host;
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+		int type;
+#endif
 		if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
 			return CURSEG_COLD_DATA_PINNED;
 
@@ -3176,6 +3179,12 @@  static int __get_segment_type_6(struct f2fs_io_info *fio)
 		}
 		if (file_is_cold(inode) || f2fs_need_compress_data(inode))
 			return CURSEG_COLD_DATA;
+
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+		type = f2fs_get_data_segment_type(inode, fio->page->index);
+		if (type != NO_CHECK_TYPE)
+			return type;
+#endif
 		if (file_is_hot(inode) ||
 				is_inode_flag_set(inode, FI_HOT_DATA) ||
 				f2fs_is_cow_file(inode))
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index df27afd71ef4..68ba8c1c2cb3 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -648,6 +648,25 @@  static ssize_t __sbi_store(struct f2fs_attr *a,
 		sbi->revoked_atomic_block = 0;
 		return count;
 	}
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+	if (!strcmp(a->attr.name, "hot_data_age_threshold")) {
+		if (t == 0 || t >= sbi->warm_data_age_threshold)
+			return -EINVAL;
+		if (t == *ui)
+			return count;
+		*ui = (unsigned int)t;
+		return count;
+	}
+
+	if (!strcmp(a->attr.name, "warm_data_age_threshold")) {
+		if (t == 0 || t <= sbi->hot_data_age_threshold)
+			return -EINVAL;
+		if (t == *ui)
+			return count;
+		*ui = (unsigned int)t;
+		return count;
+	}
+#endif
 
 	*ui = (unsigned int)t;
 
@@ -902,6 +921,11 @@  F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, peak_atomic_write, peak_atomic_write);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, committed_atomic_block, committed_atomic_block);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, revoked_atomic_block, revoked_atomic_block);
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+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);
+#endif
+
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
 	ATTR_LIST(gc_urgent_sleep_time),
@@ -995,6 +1019,10 @@  static struct attribute *f2fs_attrs[] = {
 	ATTR_LIST(peak_atomic_write),
 	ATTR_LIST(committed_atomic_block),
 	ATTR_LIST(revoked_atomic_block),
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+	ATTR_LIST(hot_data_age_threshold),
+	ATTR_LIST(warm_data_age_threshold),
+#endif
 	NULL,
 };
 ATTRIBUTE_GROUPS(f2fs);
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index b19c057ff801..0adb26397e68 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -1692,7 +1692,7 @@  DECLARE_EVENT_CLASS(f2fs_add_age_extent_node,
 		__entry->blocks = ei->last_blocks;
 	),
 
-	TP_printk("dev = (%d,%d), ino = %lu, node_cnt = %lu, "
+	TP_printk("dev = (%d,%d), ino = %lu, node_cnt = %u, "
 		"age_ext_info(fofs: %u, len: %u, age: %llu, blocks: %llu)",
 		show_dev_ino(__entry),
 		__entry->cnt,