[PATCH] f2fs: Introduce lifetime write IO statistics
From: Liu Shuoran
Date: Mon Jan 25 2016 - 22:17:26 EST
From: Shuoran Liu <liushuoran@xxxxxxxxxx>
Signed-off-by: Shuoran Liu <liushuoran@xxxxxxxxxx>
Signed-off-by: Pengyang Hou <houpengyang@xxxxxxxxxx>
---
fs/f2fs/checkpoint.c | 14 ++++++++++++++
fs/f2fs/f2fs.h | 4 ++++
fs/f2fs/super.c | 34 ++++++++++++++++++++++++++++++++++
include/linux/f2fs_fs.h | 6 ++++++
4 files changed, 58 insertions(+)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 3842af9..15dfce9 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -921,6 +921,10 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
int cp_payload_blks = __cp_payload(sbi);
block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg);
bool invalidate = false;
+ struct super_block *sb = sbi->sb;
+ struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
+ __u64 kbytes_written;
+
/*
* This avoids to conduct wrong roll-forward operations and uses
@@ -1034,6 +1038,16 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
write_data_summaries(sbi, start_blk);
start_blk += data_sum_blocks;
+
+ /* Record write statistics in HOT_NODE*/
+ kbytes_written = sbi->kbytes_written;
+ if (sb->s_bdev->bd_part)
+ kbytes_written +=
+ ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+ sbi->sectors_written_start) >> 1);
+
+ seg_i->sum_blk->info.kbytes_written = cpu_to_le64(kbytes_written);
+
if (__remain_node_summaries(cpc->reason)) {
write_node_summaries(sbi, start_blk);
start_blk += NR_CURSEG_NODE_TYPE;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ff79054..7b1b5ba 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -844,6 +844,10 @@ struct f2fs_sb_info {
struct list_head s_list;
struct mutex umount_mutex;
unsigned int shrinker_run_no;
+
+ /* For write statistics */
+ unsigned long sectors_written_start;
+ unsigned long long kbytes_written;
};
static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 3bf990b..68674da 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -126,6 +126,20 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
return NULL;
}
+static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
+ struct f2fs_sb_info *sbi, char *buf)
+{
+ struct super_block *sb = sbi->sb;
+
+ if (!sb->s_bdev->bd_part)
+ return snprintf(buf, PAGE_SIZE, "0\n");
+
+ return snprintf(buf, PAGE_SIZE, "%llu\n",
+ (unsigned long long)(sbi->kbytes_written +
+ ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+ sbi->sectors_written_start) >> 1)));
+}
+
static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf)
{
@@ -204,6 +218,9 @@ static struct f2fs_attr f2fs_attr_##_name = { \
f2fs_sbi_show, f2fs_sbi_store, \
offsetof(struct struct_name, elname))
+#define F2FS_GENERAL_RO_ATTR(name) \
+static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL)
+
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
@@ -220,6 +237,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
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_GENERAL_RO_ATTR(lifetime_write_kbytes);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = {
@@ -239,6 +257,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(ra_nid_pages),
ATTR_LIST(cp_interval),
ATTR_LIST(idle_interval),
+ ATTR_LIST(lifetime_write_kbytes),
NULL,
};
@@ -766,6 +785,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
bool need_stop_gc = false;
bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
+ if (*flags & MS_RDONLY) {
+ set_opt(sbi, FASTBOOT);
+ set_sbi_flag(sbi, SBI_IS_DIRTY);
+ }
+
sync_filesystem(sb);
/*
@@ -1242,6 +1266,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
bool retry = true, need_fsck = false;
char *options = NULL;
int recovery, i, valid_super_block;
+ struct curseg_info *seg_i;
try_onemore:
err = -EINVAL;
@@ -1372,6 +1397,15 @@ try_onemore:
goto free_nm;
}
+ /* For write statistics */
+ seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
+ if (sb->s_bdev->bd_part)
+ sbi->sectors_written_start =
+ part_stat_read(sb->s_bdev->bd_part, sectors[1]);
+
+ if(__exist_node_summaries(sbi))
+ sbi->kbytes_written = le64_to_cpu(seg_i->sum_blk->info.kbytes_written);
+
build_gc_manager(sbi);
/* get an inode for node space */
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index e59c3be..05ae034 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -387,6 +387,11 @@ struct sit_journal {
__u8 reserved[SIT_JOURNAL_RESERVED];
} __packed;
+struct f2fs_extra_info {
+ __le64 kbytes_written;
+ __u8 reserved[SUM_JOURNAL_SIZE - 10];
+} __packed;
+
/* 4KB-sized summary block structure */
struct f2fs_summary_block {
struct f2fs_summary entries[ENTRIES_IN_SUM];
@@ -398,6 +403,7 @@ struct f2fs_summary_block {
union {
struct nat_journal nat_j;
struct sit_journal sit_j;
+ struct f2fs_extra_info info;
};
struct summary_footer footer;
} __packed;
--
1.9.1