From: Baolin Liu Add a write-only mb_stats_clear sysfs knob to reset ext4 mballoc runtime statistics.This makes it easier to inspect allocator activity for a specific workload instead of using counters accumulated since mount. Signed-off-by: Baolin Liu --- fs/ext4/ext4.h | 1 + fs/ext4/mballoc.c | 31 +++++++++++++++++++++++++++++++ fs/ext4/sysfs.c | 24 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 7617e2d454ea..3a32e1a515dd 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2995,6 +2995,7 @@ int ext4_fc_record_regions(struct super_block *sb, int ino, extern const struct seq_operations ext4_mb_seq_groups_ops; extern const struct seq_operations ext4_mb_seq_structs_summary_ops; extern int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset); +extern void ext4_mb_stats_clear(struct ext4_sb_info *sbi); extern int ext4_mb_init(struct super_block *); extern void ext4_mb_release(struct super_block *); extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *, diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index bb58eafb87bc..382c91586b26 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3219,6 +3219,8 @@ int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset) } seq_printf(seq, "\treqs: %u\n", atomic_read(&sbi->s_bal_reqs)); seq_printf(seq, "\tsuccess: %u\n", atomic_read(&sbi->s_bal_success)); + seq_printf(seq, "\tblocks_allocated: %u\n", + atomic_read(&sbi->s_bal_allocated)); seq_printf(seq, "\tgroups_scanned: %u\n", atomic_read(&sbi->s_bal_groups_scanned)); @@ -4721,6 +4723,35 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) trace_ext4_mballoc_prealloc(ac); } +void ext4_mb_stats_clear(struct ext4_sb_info *sbi) +{ + int i; + + atomic_set(&sbi->s_bal_reqs, 0); + atomic_set(&sbi->s_bal_success, 0); + atomic_set(&sbi->s_bal_allocated, 0); + atomic_set(&sbi->s_bal_groups_scanned, 0); + + for (i = 0; i < EXT4_MB_NUM_CRS; i++) { + atomic64_set(&sbi->s_bal_cX_hits[i], 0); + atomic64_set(&sbi->s_bal_cX_groups_considered[i], 0); + atomic_set(&sbi->s_bal_cX_ex_scanned[i], 0); + atomic64_set(&sbi->s_bal_cX_failed[i], 0); + } + + atomic_set(&sbi->s_bal_ex_scanned, 0); + atomic_set(&sbi->s_bal_goals, 0); + atomic_set(&sbi->s_bal_stream_goals, 0); + atomic_set(&sbi->s_bal_len_goals, 0); + atomic_set(&sbi->s_bal_2orders, 0); + atomic_set(&sbi->s_bal_breaks, 0); + atomic_set(&sbi->s_mb_lost_chunks, 0); + atomic_set(&sbi->s_mb_buddies_generated, 0); + atomic64_set(&sbi->s_mb_generation_time, 0); + atomic_set(&sbi->s_mb_preallocated, 0); + atomic_set(&sbi->s_mb_discarded, 0); +} + /* * Called on failure; free up any blocks from the inode PA for this * context. We don't need this for MB_GROUP_PA because we only change diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index 923b375e017f..a5bd88a99f22 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c @@ -41,6 +41,7 @@ typedef enum { attr_pointer_atomic, attr_journal_task, attr_err_report_sec, + attr_mb_stats_clear, } attr_id_t; typedef enum { @@ -161,6 +162,25 @@ static ssize_t err_report_sec_store(struct ext4_sb_info *sbi, return count; } +static ssize_t mb_stats_clear_store(struct ext4_sb_info *sbi, + const char *buf, size_t count) +{ + int val; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = kstrtoint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val != 1) + return -EINVAL; + + ext4_mb_stats_clear(sbi); + return count; +} + static ssize_t journal_task_show(struct ext4_sb_info *sbi, char *buf) { if (!sbi->s_journal) @@ -251,6 +271,7 @@ EXT4_ATTR_OFFSET(mb_best_avail_max_trim_order, 0644, mb_order, EXT4_ATTR_OFFSET(err_report_sec, 0644, err_report_sec, ext4_sb_info, s_err_report_sec); EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); +EXT4_ATTR(mb_stats_clear, 0200, mb_stats_clear); EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); @@ -301,6 +322,7 @@ static struct attribute *ext4_attrs[] = { ATTR_LIST(inode_readahead_blks), ATTR_LIST(inode_goal), ATTR_LIST(mb_stats), + ATTR_LIST(mb_stats_clear), ATTR_LIST(mb_max_to_scan), ATTR_LIST(mb_min_to_scan), ATTR_LIST(mb_order2_req), @@ -561,6 +583,8 @@ static ssize_t ext4_attr_store(struct kobject *kobj, return trigger_test_error(sbi, buf, len); case attr_err_report_sec: return err_report_sec_store(sbi, buf, len); + case attr_mb_stats_clear: + return mb_stats_clear_store(sbi, buf, len); default: return ext4_generic_attr_store(a, sbi, buf, len); } -- 2.51.0