Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: introduce lifetime write IO statistics

This patch introduces lifetime IO write statistics exposed to the sysfs interface.
The write IO amount is obtained from block layer, accumulated in the file system and
stored in the hot node summary of checkpoint.

Signed-off-by: Shuoran Liu <liushuoran@huawei.com>
Signed-off-by: Pengyang Hou <houpengyang@huawei.com>
[Jaegeuk Kim: add sysfs documentation]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Shuoran Liu and committed by
Jaegeuk Kim
8f1dbbbb 6fe2bc95

+78 -3
+6
Documentation/ABI/testing/sysfs-fs-f2fs
··· 106 106 Controls dirty nat entries ratio threshold, if current 107 107 ratio exceeds configured threshold, checkpoint will 108 108 be triggered for flushing dirty nat entries. 109 + 110 + What: /sys/fs/f2fs/<disk>/lifetime_write_kbytes 111 + Date: January 2016 112 + Contact: "Shuoran Liu" <liushuoran@huawei.com> 113 + Description: 114 + Shows total written kbytes issued to disk.
+11
fs/f2fs/checkpoint.c
··· 921 921 int cp_payload_blks = __cp_payload(sbi); 922 922 block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg); 923 923 bool invalidate = false; 924 + struct super_block *sb = sbi->sb; 925 + struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 926 + u64 kbytes_written; 924 927 925 928 /* 926 929 * This avoids to conduct wrong roll-forward operations and uses ··· 1037 1034 1038 1035 write_data_summaries(sbi, start_blk); 1039 1036 start_blk += data_sum_blocks; 1037 + 1038 + /* Record write statistics in the hot node summary */ 1039 + kbytes_written = sbi->kbytes_written; 1040 + if (sb->s_bdev->bd_part) 1041 + kbytes_written += BD_PART_WRITTEN(sbi); 1042 + 1043 + seg_i->sum_blk->info.kbytes_written = cpu_to_le64(kbytes_written); 1044 + 1040 1045 if (__remain_node_summaries(cpc->reason)) { 1041 1046 write_node_summaries(sbi, start_blk); 1042 1047 start_blk += NR_CURSEG_NODE_TYPE;
+11
fs/f2fs/f2fs.h
··· 846 846 struct list_head s_list; 847 847 struct mutex umount_mutex; 848 848 unsigned int shrinker_run_no; 849 + 850 + /* For write statistics */ 851 + u64 sectors_written_start; 852 + u64 kbytes_written; 849 853 }; 854 + 855 + /* For write statistics. Suppose sector size is 512 bytes, 856 + * and the return value is in kbytes. s is of struct f2fs_sb_info. 857 + */ 858 + #define BD_PART_WRITTEN(s) \ 859 + (((u64)part_stat_read(s->sb->s_bdev->bd_part, sectors[1]) - \ 860 + s->sectors_written_start) >> 1) 850 861 851 862 static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type) 852 863 {
+37 -2
fs/f2fs/super.c
··· 126 126 return NULL; 127 127 } 128 128 129 + static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, 130 + struct f2fs_sb_info *sbi, char *buf) 131 + { 132 + struct super_block *sb = sbi->sb; 133 + 134 + if (!sb->s_bdev->bd_part) 135 + return snprintf(buf, PAGE_SIZE, "0\n"); 136 + 137 + return snprintf(buf, PAGE_SIZE, "%llu\n", 138 + (unsigned long long)(sbi->kbytes_written + 139 + BD_PART_WRITTEN(sbi))); 140 + } 141 + 129 142 static ssize_t f2fs_sbi_show(struct f2fs_attr *a, 130 143 struct f2fs_sb_info *sbi, char *buf) 131 144 { ··· 217 204 f2fs_sbi_show, f2fs_sbi_store, \ 218 205 offsetof(struct struct_name, elname)) 219 206 207 + #define F2FS_GENERAL_RO_ATTR(name) \ 208 + static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) 209 + 220 210 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); 221 211 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); 222 212 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); ··· 237 221 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); 238 222 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); 239 223 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); 224 + F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); 240 225 241 226 #define ATTR_LIST(name) (&f2fs_attr_##name.attr) 242 227 static struct attribute *f2fs_attrs[] = { ··· 258 241 ATTR_LIST(dirty_nats_ratio), 259 242 ATTR_LIST(cp_interval), 260 243 ATTR_LIST(idle_interval), 244 + ATTR_LIST(lifetime_write_kbytes), 261 245 NULL, 262 246 }; 263 247 ··· 786 768 bool need_stop_gc = false; 787 769 bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); 788 770 789 - sync_filesystem(sb); 790 - 791 771 /* 792 772 * Save the old mount options in case we 793 773 * need to restore them. 794 774 */ 795 775 org_mount_opt = sbi->mount_opt; 796 776 active_logs = sbi->active_logs; 777 + 778 + if (*flags & MS_RDONLY) { 779 + set_opt(sbi, FASTBOOT); 780 + set_sbi_flag(sbi, SBI_IS_DIRTY); 781 + } 782 + 783 + sync_filesystem(sb); 797 784 798 785 sbi->mount_opt.opt = 0; 799 786 default_options(sbi); ··· 1267 1244 bool retry = true, need_fsck = false; 1268 1245 char *options = NULL; 1269 1246 int recovery, i, valid_super_block; 1247 + struct curseg_info *seg_i; 1270 1248 1271 1249 try_onemore: 1272 1250 err = -EINVAL; ··· 1397 1373 "Failed to initialize F2FS node manager"); 1398 1374 goto free_nm; 1399 1375 } 1376 + 1377 + /* For write statistics */ 1378 + if (sb->s_bdev->bd_part) 1379 + sbi->sectors_written_start = 1380 + (u64)part_stat_read(sb->s_bdev->bd_part, sectors[1]); 1381 + 1382 + /* Read accumulated write IO statistics if exists */ 1383 + seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 1384 + if (__exist_node_summaries(sbi)) 1385 + sbi->kbytes_written = 1386 + le64_to_cpu(seg_i->sum_blk->info.kbytes_written); 1400 1387 1401 1388 build_gc_manager(sbi); 1402 1389
+13 -1
include/linux/f2fs_fs.h
··· 358 358 sizeof(struct sit_journal_entry)) 359 359 #define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ 360 360 sizeof(struct sit_journal_entry)) 361 + 362 + /* Reserved area should make size of f2fs_extra_info equals to 363 + * that of nat_journal and sit_journal. 364 + */ 365 + #define EXTRA_INFO_RESERVED (SUM_JOURNAL_SIZE - 2 - 8) 366 + 361 367 /* 362 368 * frequently updated NAT/SIT entries can be stored in the spare area in 363 369 * summary blocks ··· 393 387 __u8 reserved[SIT_JOURNAL_RESERVED]; 394 388 } __packed; 395 389 390 + struct f2fs_extra_info { 391 + __le64 kbytes_written; 392 + __u8 reserved[EXTRA_INFO_RESERVED]; 393 + } __packed; 394 + 396 395 /* 4KB-sized summary block structure */ 397 396 struct f2fs_summary_block { 398 397 struct f2fs_summary entries[ENTRIES_IN_SUM]; ··· 405 394 __le16 n_nats; 406 395 __le16 n_sits; 407 396 }; 408 - /* spare area is used by NAT or SIT journals */ 397 + /* spare area is used by NAT or SIT journals or extra info */ 409 398 union { 410 399 struct nat_journal nat_j; 411 400 struct sit_journal sit_j; 401 + struct f2fs_extra_info info; 412 402 }; 413 403 struct summary_footer footer; 414 404 } __packed;