diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-fs-f2fs | 6 | ||||
-rw-r--r-- | fs/f2fs/checkpoint.c | 11 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 11 | ||||
-rw-r--r-- | fs/f2fs/super.c | 39 | ||||
-rw-r--r-- | include/linux/f2fs_fs.h | 14 |
5 files changed, 78 insertions, 3 deletions
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 523cb9d4e272..a809f6005f14 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs | |||
@@ -106,3 +106,9 @@ Description: | |||
106 | Controls dirty nat entries ratio threshold, if current | 106 | Controls dirty nat entries ratio threshold, if current |
107 | ratio exceeds configured threshold, checkpoint will | 107 | ratio exceeds configured threshold, checkpoint will |
108 | be triggered for flushing dirty nat entries. | 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. | ||
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 4b6f9c08f6fa..112e19fdbe08 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -921,6 +921,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
921 | int cp_payload_blks = __cp_payload(sbi); | 921 | int cp_payload_blks = __cp_payload(sbi); |
922 | block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg); | 922 | block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg); |
923 | bool invalidate = false; | 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 | * This avoids to conduct wrong roll-forward operations and uses | 929 | * This avoids to conduct wrong roll-forward operations and uses |
@@ -1034,6 +1037,14 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1034 | 1037 | ||
1035 | write_data_summaries(sbi, start_blk); | 1038 | write_data_summaries(sbi, start_blk); |
1036 | start_blk += data_sum_blocks; | 1039 | start_blk += data_sum_blocks; |
1040 | |||
1041 | /* Record write statistics in the hot node summary */ | ||
1042 | kbytes_written = sbi->kbytes_written; | ||
1043 | if (sb->s_bdev->bd_part) | ||
1044 | kbytes_written += BD_PART_WRITTEN(sbi); | ||
1045 | |||
1046 | seg_i->sum_blk->info.kbytes_written = cpu_to_le64(kbytes_written); | ||
1047 | |||
1037 | if (__remain_node_summaries(cpc->reason)) { | 1048 | if (__remain_node_summaries(cpc->reason)) { |
1038 | write_node_summaries(sbi, start_blk); | 1049 | write_node_summaries(sbi, start_blk); |
1039 | start_blk += NR_CURSEG_NODE_TYPE; | 1050 | start_blk += NR_CURSEG_NODE_TYPE; |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 4e7eab9f3f5a..5b6fd541551c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -846,8 +846,19 @@ struct f2fs_sb_info { | |||
846 | struct list_head s_list; | 846 | struct list_head s_list; |
847 | struct mutex umount_mutex; | 847 | struct mutex umount_mutex; |
848 | unsigned int shrinker_run_no; | 848 | unsigned int shrinker_run_no; |
849 | |||
850 | /* For write statistics */ | ||
851 | u64 sectors_written_start; | ||
852 | u64 kbytes_written; | ||
849 | }; | 853 | }; |
850 | 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) | ||
861 | |||
851 | static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type) | 862 | static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type) |
852 | { | 863 | { |
853 | sbi->last_time[type] = jiffies; | 864 | sbi->last_time[type] = jiffies; |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 0ea5bcccab6d..58d9a5574bb0 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -126,6 +126,19 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | |||
126 | return NULL; | 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 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | 142 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, |
130 | struct f2fs_sb_info *sbi, char *buf) | 143 | struct f2fs_sb_info *sbi, char *buf) |
131 | { | 144 | { |
@@ -204,6 +217,9 @@ static struct f2fs_attr f2fs_attr_##_name = { \ | |||
204 | f2fs_sbi_show, f2fs_sbi_store, \ | 217 | f2fs_sbi_show, f2fs_sbi_store, \ |
205 | offsetof(struct struct_name, elname)) | 218 | offsetof(struct struct_name, elname)) |
206 | 219 | ||
220 | #define F2FS_GENERAL_RO_ATTR(name) \ | ||
221 | static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) | ||
222 | |||
207 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); | 223 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); |
208 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); | 224 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); |
209 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); | 225 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); |
@@ -221,6 +237,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); | |||
221 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); | 237 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); |
222 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); | 238 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); |
223 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); | 239 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); |
240 | F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); | ||
224 | 241 | ||
225 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) | 242 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) |
226 | static struct attribute *f2fs_attrs[] = { | 243 | static struct attribute *f2fs_attrs[] = { |
@@ -241,6 +258,7 @@ static struct attribute *f2fs_attrs[] = { | |||
241 | ATTR_LIST(dirty_nats_ratio), | 258 | ATTR_LIST(dirty_nats_ratio), |
242 | ATTR_LIST(cp_interval), | 259 | ATTR_LIST(cp_interval), |
243 | ATTR_LIST(idle_interval), | 260 | ATTR_LIST(idle_interval), |
261 | ATTR_LIST(lifetime_write_kbytes), | ||
244 | NULL, | 262 | NULL, |
245 | }; | 263 | }; |
246 | 264 | ||
@@ -768,8 +786,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) | |||
768 | bool need_stop_gc = false; | 786 | bool need_stop_gc = false; |
769 | bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); | 787 | bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); |
770 | 788 | ||
771 | sync_filesystem(sb); | ||
772 | |||
773 | /* | 789 | /* |
774 | * Save the old mount options in case we | 790 | * Save the old mount options in case we |
775 | * need to restore them. | 791 | * need to restore them. |
@@ -777,6 +793,13 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) | |||
777 | org_mount_opt = sbi->mount_opt; | 793 | org_mount_opt = sbi->mount_opt; |
778 | active_logs = sbi->active_logs; | 794 | active_logs = sbi->active_logs; |
779 | 795 | ||
796 | if (*flags & MS_RDONLY) { | ||
797 | set_opt(sbi, FASTBOOT); | ||
798 | set_sbi_flag(sbi, SBI_IS_DIRTY); | ||
799 | } | ||
800 | |||
801 | sync_filesystem(sb); | ||
802 | |||
780 | sbi->mount_opt.opt = 0; | 803 | sbi->mount_opt.opt = 0; |
781 | default_options(sbi); | 804 | default_options(sbi); |
782 | 805 | ||
@@ -1244,6 +1267,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
1244 | bool retry = true, need_fsck = false; | 1267 | bool retry = true, need_fsck = false; |
1245 | char *options = NULL; | 1268 | char *options = NULL; |
1246 | int recovery, i, valid_super_block; | 1269 | int recovery, i, valid_super_block; |
1270 | struct curseg_info *seg_i; | ||
1247 | 1271 | ||
1248 | try_onemore: | 1272 | try_onemore: |
1249 | err = -EINVAL; | 1273 | err = -EINVAL; |
@@ -1374,6 +1398,17 @@ try_onemore: | |||
1374 | goto free_nm; | 1398 | goto free_nm; |
1375 | } | 1399 | } |
1376 | 1400 | ||
1401 | /* For write statistics */ | ||
1402 | if (sb->s_bdev->bd_part) | ||
1403 | sbi->sectors_written_start = | ||
1404 | (u64)part_stat_read(sb->s_bdev->bd_part, sectors[1]); | ||
1405 | |||
1406 | /* Read accumulated write IO statistics if exists */ | ||
1407 | seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); | ||
1408 | if (__exist_node_summaries(sbi)) | ||
1409 | sbi->kbytes_written = | ||
1410 | le64_to_cpu(seg_i->sum_blk->info.kbytes_written); | ||
1411 | |||
1377 | build_gc_manager(sbi); | 1412 | build_gc_manager(sbi); |
1378 | 1413 | ||
1379 | /* get an inode for node space */ | 1414 | /* get an inode for node space */ |
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index e59c3be92106..67aa01df777d 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h | |||
@@ -358,6 +358,12 @@ struct summary_footer { | |||
358 | sizeof(struct sit_journal_entry)) | 358 | sizeof(struct sit_journal_entry)) |
359 | #define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ | 359 | #define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ |
360 | sizeof(struct sit_journal_entry)) | 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 | * frequently updated NAT/SIT entries can be stored in the spare area in | 368 | * frequently updated NAT/SIT entries can be stored in the spare area in |
363 | * summary blocks | 369 | * summary blocks |
@@ -387,6 +393,11 @@ struct sit_journal { | |||
387 | __u8 reserved[SIT_JOURNAL_RESERVED]; | 393 | __u8 reserved[SIT_JOURNAL_RESERVED]; |
388 | } __packed; | 394 | } __packed; |
389 | 395 | ||
396 | struct f2fs_extra_info { | ||
397 | __le64 kbytes_written; | ||
398 | __u8 reserved[EXTRA_INFO_RESERVED]; | ||
399 | } __packed; | ||
400 | |||
390 | /* 4KB-sized summary block structure */ | 401 | /* 4KB-sized summary block structure */ |
391 | struct f2fs_summary_block { | 402 | struct f2fs_summary_block { |
392 | struct f2fs_summary entries[ENTRIES_IN_SUM]; | 403 | struct f2fs_summary entries[ENTRIES_IN_SUM]; |
@@ -394,10 +405,11 @@ struct f2fs_summary_block { | |||
394 | __le16 n_nats; | 405 | __le16 n_nats; |
395 | __le16 n_sits; | 406 | __le16 n_sits; |
396 | }; | 407 | }; |
397 | /* spare area is used by NAT or SIT journals */ | 408 | /* spare area is used by NAT or SIT journals or extra info */ |
398 | union { | 409 | union { |
399 | struct nat_journal nat_j; | 410 | struct nat_journal nat_j; |
400 | struct sit_journal sit_j; | 411 | struct sit_journal sit_j; |
412 | struct f2fs_extra_info info; | ||
401 | }; | 413 | }; |
402 | struct summary_footer footer; | 414 | struct summary_footer footer; |
403 | } __packed; | 415 | } __packed; |