1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * f2fs sysfs interface |
4 | * |
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. |
6 | * http://www.samsung.com/ |
7 | * Copyright (c) 2017 Chao Yu <chao@kernel.org> |
8 | */ |
9 | #include <linux/compiler.h> |
10 | #include <linux/proc_fs.h> |
11 | #include <linux/f2fs_fs.h> |
12 | #include <linux/seq_file.h> |
13 | #include <linux/unicode.h> |
14 | #include <linux/ioprio.h> |
15 | #include <linux/sysfs.h> |
16 | |
17 | #include "f2fs.h" |
18 | #include "segment.h" |
19 | #include "gc.h" |
20 | #include "iostat.h" |
21 | #include <trace/events/f2fs.h> |
22 | |
23 | static struct proc_dir_entry *f2fs_proc_root; |
24 | |
25 | /* Sysfs support for f2fs */ |
26 | enum { |
27 | GC_THREAD, /* struct f2fs_gc_thread */ |
28 | SM_INFO, /* struct f2fs_sm_info */ |
29 | DCC_INFO, /* struct discard_cmd_control */ |
30 | NM_INFO, /* struct f2fs_nm_info */ |
31 | F2FS_SBI, /* struct f2fs_sb_info */ |
32 | #ifdef CONFIG_F2FS_STAT_FS |
33 | STAT_INFO, /* struct f2fs_stat_info */ |
34 | #endif |
35 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
36 | FAULT_INFO_RATE, /* struct f2fs_fault_info */ |
37 | FAULT_INFO_TYPE, /* struct f2fs_fault_info */ |
38 | #endif |
39 | RESERVED_BLOCKS, /* struct f2fs_sb_info */ |
40 | CPRC_INFO, /* struct ckpt_req_control */ |
41 | ATGC_INFO, /* struct atgc_management */ |
42 | }; |
43 | |
44 | static const char *gc_mode_names[MAX_GC_MODE] = { |
45 | "GC_NORMAL" , |
46 | "GC_IDLE_CB" , |
47 | "GC_IDLE_GREEDY" , |
48 | "GC_IDLE_AT" , |
49 | "GC_URGENT_HIGH" , |
50 | "GC_URGENT_LOW" , |
51 | "GC_URGENT_MID" |
52 | }; |
53 | |
54 | struct f2fs_attr { |
55 | struct attribute attr; |
56 | ssize_t (*show)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf); |
57 | ssize_t (*store)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, |
58 | const char *buf, size_t len); |
59 | int struct_type; |
60 | int offset; |
61 | int id; |
62 | }; |
63 | |
64 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, |
65 | struct f2fs_sb_info *sbi, char *buf); |
66 | |
67 | static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) |
68 | { |
69 | if (struct_type == GC_THREAD) |
70 | return (unsigned char *)sbi->gc_thread; |
71 | else if (struct_type == SM_INFO) |
72 | return (unsigned char *)SM_I(sbi); |
73 | else if (struct_type == DCC_INFO) |
74 | return (unsigned char *)SM_I(sbi)->dcc_info; |
75 | else if (struct_type == NM_INFO) |
76 | return (unsigned char *)NM_I(sbi); |
77 | else if (struct_type == F2FS_SBI || struct_type == RESERVED_BLOCKS) |
78 | return (unsigned char *)sbi; |
79 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
80 | else if (struct_type == FAULT_INFO_RATE || |
81 | struct_type == FAULT_INFO_TYPE) |
82 | return (unsigned char *)&F2FS_OPTION(sbi).fault_info; |
83 | #endif |
84 | #ifdef CONFIG_F2FS_STAT_FS |
85 | else if (struct_type == STAT_INFO) |
86 | return (unsigned char *)F2FS_STAT(sbi); |
87 | #endif |
88 | else if (struct_type == CPRC_INFO) |
89 | return (unsigned char *)&sbi->cprc_info; |
90 | else if (struct_type == ATGC_INFO) |
91 | return (unsigned char *)&sbi->am; |
92 | return NULL; |
93 | } |
94 | |
95 | static ssize_t dirty_segments_show(struct f2fs_attr *a, |
96 | struct f2fs_sb_info *sbi, char *buf) |
97 | { |
98 | return sysfs_emit(buf, fmt: "%llu\n" , |
99 | (unsigned long long)(dirty_segments(sbi))); |
100 | } |
101 | |
102 | static ssize_t free_segments_show(struct f2fs_attr *a, |
103 | struct f2fs_sb_info *sbi, char *buf) |
104 | { |
105 | return sysfs_emit(buf, fmt: "%llu\n" , |
106 | (unsigned long long)(free_segments(sbi))); |
107 | } |
108 | |
109 | static ssize_t ovp_segments_show(struct f2fs_attr *a, |
110 | struct f2fs_sb_info *sbi, char *buf) |
111 | { |
112 | return sysfs_emit(buf, fmt: "%llu\n" , |
113 | (unsigned long long)(overprovision_segments(sbi))); |
114 | } |
115 | |
116 | static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, |
117 | struct f2fs_sb_info *sbi, char *buf) |
118 | { |
119 | return sysfs_emit(buf, fmt: "%llu\n" , |
120 | (unsigned long long)(sbi->kbytes_written + |
121 | ((f2fs_get_sectors_written(sbi) - |
122 | sbi->sectors_written_start) >> 1))); |
123 | } |
124 | |
125 | static ssize_t sb_status_show(struct f2fs_attr *a, |
126 | struct f2fs_sb_info *sbi, char *buf) |
127 | { |
128 | return sysfs_emit(buf, fmt: "%lx\n" , sbi->s_flag); |
129 | } |
130 | |
131 | static ssize_t cp_status_show(struct f2fs_attr *a, |
132 | struct f2fs_sb_info *sbi, char *buf) |
133 | { |
134 | return sysfs_emit(buf, fmt: "%x\n" , le32_to_cpu(F2FS_CKPT(sbi)->ckpt_flags)); |
135 | } |
136 | |
137 | static ssize_t pending_discard_show(struct f2fs_attr *a, |
138 | struct f2fs_sb_info *sbi, char *buf) |
139 | { |
140 | if (!SM_I(sbi)->dcc_info) |
141 | return -EINVAL; |
142 | return sysfs_emit(buf, fmt: "%llu\n" , (unsigned long long)atomic_read( |
143 | v: &SM_I(sbi)->dcc_info->discard_cmd_cnt)); |
144 | } |
145 | |
146 | static ssize_t issued_discard_show(struct f2fs_attr *a, |
147 | struct f2fs_sb_info *sbi, char *buf) |
148 | { |
149 | if (!SM_I(sbi)->dcc_info) |
150 | return -EINVAL; |
151 | return sysfs_emit(buf, fmt: "%llu\n" , (unsigned long long)atomic_read( |
152 | v: &SM_I(sbi)->dcc_info->issued_discard)); |
153 | } |
154 | |
155 | static ssize_t queued_discard_show(struct f2fs_attr *a, |
156 | struct f2fs_sb_info *sbi, char *buf) |
157 | { |
158 | if (!SM_I(sbi)->dcc_info) |
159 | return -EINVAL; |
160 | return sysfs_emit(buf, fmt: "%llu\n" , (unsigned long long)atomic_read( |
161 | v: &SM_I(sbi)->dcc_info->queued_discard)); |
162 | } |
163 | |
164 | static ssize_t undiscard_blks_show(struct f2fs_attr *a, |
165 | struct f2fs_sb_info *sbi, char *buf) |
166 | { |
167 | if (!SM_I(sbi)->dcc_info) |
168 | return -EINVAL; |
169 | return sysfs_emit(buf, fmt: "%u\n" , |
170 | SM_I(sbi)->dcc_info->undiscard_blks); |
171 | } |
172 | |
173 | static ssize_t gc_mode_show(struct f2fs_attr *a, |
174 | struct f2fs_sb_info *sbi, char *buf) |
175 | { |
176 | return sysfs_emit(buf, fmt: "%s\n" , gc_mode_names[sbi->gc_mode]); |
177 | } |
178 | |
179 | static ssize_t features_show(struct f2fs_attr *a, |
180 | struct f2fs_sb_info *sbi, char *buf) |
181 | { |
182 | int len = 0; |
183 | |
184 | if (f2fs_sb_has_encrypt(sbi)) |
185 | len += scnprintf(buf, PAGE_SIZE - len, fmt: "%s" , |
186 | "encryption" ); |
187 | if (f2fs_sb_has_blkzoned(sbi)) |
188 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
189 | len ? ", " : "" , "blkzoned" ); |
190 | if (f2fs_sb_has_extra_attr(sbi)) |
191 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
192 | len ? ", " : "" , "extra_attr" ); |
193 | if (f2fs_sb_has_project_quota(sbi)) |
194 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
195 | len ? ", " : "" , "projquota" ); |
196 | if (f2fs_sb_has_inode_chksum(sbi)) |
197 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
198 | len ? ", " : "" , "inode_checksum" ); |
199 | if (f2fs_sb_has_flexible_inline_xattr(sbi)) |
200 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
201 | len ? ", " : "" , "flexible_inline_xattr" ); |
202 | if (f2fs_sb_has_quota_ino(sbi)) |
203 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
204 | len ? ", " : "" , "quota_ino" ); |
205 | if (f2fs_sb_has_inode_crtime(sbi)) |
206 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
207 | len ? ", " : "" , "inode_crtime" ); |
208 | if (f2fs_sb_has_lost_found(sbi)) |
209 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
210 | len ? ", " : "" , "lost_found" ); |
211 | if (f2fs_sb_has_verity(sbi)) |
212 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
213 | len ? ", " : "" , "verity" ); |
214 | if (f2fs_sb_has_sb_chksum(sbi)) |
215 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
216 | len ? ", " : "" , "sb_checksum" ); |
217 | if (f2fs_sb_has_casefold(sbi)) |
218 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
219 | len ? ", " : "" , "casefold" ); |
220 | if (f2fs_sb_has_readonly(sbi)) |
221 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
222 | len ? ", " : "" , "readonly" ); |
223 | if (f2fs_sb_has_compression(sbi)) |
224 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
225 | len ? ", " : "" , "compression" ); |
226 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s%s" , |
227 | len ? ", " : "" , "pin_file" ); |
228 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "\n" ); |
229 | return len; |
230 | } |
231 | |
232 | static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, |
233 | struct f2fs_sb_info *sbi, char *buf) |
234 | { |
235 | return sysfs_emit(buf, fmt: "%u\n" , sbi->current_reserved_blocks); |
236 | } |
237 | |
238 | static ssize_t unusable_show(struct f2fs_attr *a, |
239 | struct f2fs_sb_info *sbi, char *buf) |
240 | { |
241 | block_t unusable; |
242 | |
243 | if (test_opt(sbi, DISABLE_CHECKPOINT)) |
244 | unusable = sbi->unusable_block_count; |
245 | else |
246 | unusable = f2fs_get_unusable_blocks(sbi); |
247 | return sysfs_emit(buf, fmt: "%llu\n" , (unsigned long long)unusable); |
248 | } |
249 | |
250 | static ssize_t encoding_show(struct f2fs_attr *a, |
251 | struct f2fs_sb_info *sbi, char *buf) |
252 | { |
253 | #if IS_ENABLED(CONFIG_UNICODE) |
254 | struct super_block *sb = sbi->sb; |
255 | |
256 | if (f2fs_sb_has_casefold(sbi)) |
257 | return sysfs_emit(buf, fmt: "UTF-8 (%d.%d.%d)\n" , |
258 | (sb->s_encoding->version >> 16) & 0xff, |
259 | (sb->s_encoding->version >> 8) & 0xff, |
260 | sb->s_encoding->version & 0xff); |
261 | #endif |
262 | return sysfs_emit(buf, fmt: "(none)\n" ); |
263 | } |
264 | |
265 | static ssize_t mounted_time_sec_show(struct f2fs_attr *a, |
266 | struct f2fs_sb_info *sbi, char *buf) |
267 | { |
268 | return sysfs_emit(buf, fmt: "%llu\n" , SIT_I(sbi)->mounted_time); |
269 | } |
270 | |
271 | #ifdef CONFIG_F2FS_STAT_FS |
272 | static ssize_t moved_blocks_foreground_show(struct f2fs_attr *a, |
273 | struct f2fs_sb_info *sbi, char *buf) |
274 | { |
275 | struct f2fs_stat_info *si = F2FS_STAT(sbi); |
276 | |
277 | return sysfs_emit(buf, fmt: "%llu\n" , |
278 | (unsigned long long)(si->tot_blks - |
279 | (si->bg_data_blks + si->bg_node_blks))); |
280 | } |
281 | |
282 | static ssize_t moved_blocks_background_show(struct f2fs_attr *a, |
283 | struct f2fs_sb_info *sbi, char *buf) |
284 | { |
285 | struct f2fs_stat_info *si = F2FS_STAT(sbi); |
286 | |
287 | return sysfs_emit(buf, fmt: "%llu\n" , |
288 | (unsigned long long)(si->bg_data_blks + si->bg_node_blks)); |
289 | } |
290 | |
291 | static ssize_t avg_vblocks_show(struct f2fs_attr *a, |
292 | struct f2fs_sb_info *sbi, char *buf) |
293 | { |
294 | struct f2fs_stat_info *si = F2FS_STAT(sbi); |
295 | |
296 | si->dirty_count = dirty_segments(sbi); |
297 | f2fs_update_sit_info(sbi); |
298 | return sysfs_emit(buf, fmt: "%llu\n" , (unsigned long long)(si->avg_vblocks)); |
299 | } |
300 | #endif |
301 | |
302 | static ssize_t main_blkaddr_show(struct f2fs_attr *a, |
303 | struct f2fs_sb_info *sbi, char *buf) |
304 | { |
305 | return sysfs_emit(buf, fmt: "%llu\n" , |
306 | (unsigned long long)MAIN_BLKADDR(sbi)); |
307 | } |
308 | |
309 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, |
310 | struct f2fs_sb_info *sbi, char *buf) |
311 | { |
312 | unsigned char *ptr = NULL; |
313 | unsigned int *ui; |
314 | |
315 | ptr = __struct_ptr(sbi, struct_type: a->struct_type); |
316 | if (!ptr) |
317 | return -EINVAL; |
318 | |
319 | if (!strcmp(a->attr.name, "extension_list" )) { |
320 | __u8 (*extlist)[F2FS_EXTENSION_LEN] = |
321 | sbi->raw_super->extension_list; |
322 | int cold_count = le32_to_cpu(sbi->raw_super->extension_count); |
323 | int hot_count = sbi->raw_super->hot_ext_count; |
324 | int len = 0, i; |
325 | |
326 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, |
327 | fmt: "cold file extension:\n" ); |
328 | for (i = 0; i < cold_count; i++) |
329 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s\n" , |
330 | extlist[i]); |
331 | |
332 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, |
333 | fmt: "hot file extension:\n" ); |
334 | for (i = cold_count; i < cold_count + hot_count; i++) |
335 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%s\n" , |
336 | extlist[i]); |
337 | return len; |
338 | } |
339 | |
340 | if (!strcmp(a->attr.name, "ckpt_thread_ioprio" )) { |
341 | struct ckpt_req_control *cprc = &sbi->cprc_info; |
342 | int class = IOPRIO_PRIO_CLASS(cprc->ckpt_thread_ioprio); |
343 | int data = IOPRIO_PRIO_DATA(cprc->ckpt_thread_ioprio); |
344 | |
345 | if (class != IOPRIO_CLASS_RT && class != IOPRIO_CLASS_BE) |
346 | return -EINVAL; |
347 | |
348 | return sysfs_emit(buf, fmt: "%s,%d\n" , |
349 | class == IOPRIO_CLASS_RT ? "rt" : "be" , data); |
350 | } |
351 | |
352 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
353 | if (!strcmp(a->attr.name, "compr_written_block" )) |
354 | return sysfs_emit(buf, fmt: "%llu\n" , sbi->compr_written_block); |
355 | |
356 | if (!strcmp(a->attr.name, "compr_saved_block" )) |
357 | return sysfs_emit(buf, fmt: "%llu\n" , sbi->compr_saved_block); |
358 | |
359 | if (!strcmp(a->attr.name, "compr_new_inode" )) |
360 | return sysfs_emit(buf, fmt: "%u\n" , sbi->compr_new_inode); |
361 | #endif |
362 | |
363 | if (!strcmp(a->attr.name, "gc_segment_mode" )) |
364 | return sysfs_emit(buf, fmt: "%u\n" , sbi->gc_segment_mode); |
365 | |
366 | if (!strcmp(a->attr.name, "gc_reclaimed_segments" )) { |
367 | return sysfs_emit(buf, fmt: "%u\n" , |
368 | sbi->gc_reclaimed_segs[sbi->gc_segment_mode]); |
369 | } |
370 | |
371 | if (!strcmp(a->attr.name, "current_atomic_write" )) { |
372 | s64 current_write = atomic64_read(v: &sbi->current_atomic_write); |
373 | |
374 | return sysfs_emit(buf, fmt: "%lld\n" , current_write); |
375 | } |
376 | |
377 | if (!strcmp(a->attr.name, "peak_atomic_write" )) |
378 | return sysfs_emit(buf, fmt: "%lld\n" , sbi->peak_atomic_write); |
379 | |
380 | if (!strcmp(a->attr.name, "committed_atomic_block" )) |
381 | return sysfs_emit(buf, fmt: "%llu\n" , sbi->committed_atomic_block); |
382 | |
383 | if (!strcmp(a->attr.name, "revoked_atomic_block" )) |
384 | return sysfs_emit(buf, fmt: "%llu\n" , sbi->revoked_atomic_block); |
385 | |
386 | #ifdef CONFIG_F2FS_STAT_FS |
387 | if (!strcmp(a->attr.name, "cp_foreground_calls" )) |
388 | return sysfs_emit(buf, fmt: "%d\n" , |
389 | atomic_read(v: &sbi->cp_call_count[TOTAL_CALL]) - |
390 | atomic_read(v: &sbi->cp_call_count[BACKGROUND])); |
391 | if (!strcmp(a->attr.name, "cp_background_calls" )) |
392 | return sysfs_emit(buf, fmt: "%d\n" , |
393 | atomic_read(v: &sbi->cp_call_count[BACKGROUND])); |
394 | #endif |
395 | |
396 | ui = (unsigned int *)(ptr + a->offset); |
397 | |
398 | return sysfs_emit(buf, fmt: "%u\n" , *ui); |
399 | } |
400 | |
401 | static ssize_t __sbi_store(struct f2fs_attr *a, |
402 | struct f2fs_sb_info *sbi, |
403 | const char *buf, size_t count) |
404 | { |
405 | unsigned char *ptr; |
406 | unsigned long t; |
407 | unsigned int *ui; |
408 | ssize_t ret; |
409 | |
410 | ptr = __struct_ptr(sbi, struct_type: a->struct_type); |
411 | if (!ptr) |
412 | return -EINVAL; |
413 | |
414 | if (!strcmp(a->attr.name, "extension_list" )) { |
415 | const char *name = strim((char *)buf); |
416 | bool set = true, hot; |
417 | |
418 | if (!strncmp(name, "[h]" , 3)) |
419 | hot = true; |
420 | else if (!strncmp(name, "[c]" , 3)) |
421 | hot = false; |
422 | else |
423 | return -EINVAL; |
424 | |
425 | name += 3; |
426 | |
427 | if (*name == '!') { |
428 | name++; |
429 | set = false; |
430 | } |
431 | |
432 | if (!strlen(name) || strlen(name) >= F2FS_EXTENSION_LEN) |
433 | return -EINVAL; |
434 | |
435 | f2fs_down_write(sem: &sbi->sb_lock); |
436 | |
437 | ret = f2fs_update_extension_list(sbi, name, hot, set); |
438 | if (ret) |
439 | goto out; |
440 | |
441 | ret = f2fs_commit_super(sbi, recover: false); |
442 | if (ret) |
443 | f2fs_update_extension_list(sbi, name, hot, set: !set); |
444 | out: |
445 | f2fs_up_write(sem: &sbi->sb_lock); |
446 | return ret ? ret : count; |
447 | } |
448 | |
449 | if (!strcmp(a->attr.name, "ckpt_thread_ioprio" )) { |
450 | const char *name = strim((char *)buf); |
451 | struct ckpt_req_control *cprc = &sbi->cprc_info; |
452 | int class; |
453 | long data; |
454 | int ret; |
455 | |
456 | if (!strncmp(name, "rt," , 3)) |
457 | class = IOPRIO_CLASS_RT; |
458 | else if (!strncmp(name, "be," , 3)) |
459 | class = IOPRIO_CLASS_BE; |
460 | else |
461 | return -EINVAL; |
462 | |
463 | name += 3; |
464 | ret = kstrtol(s: name, base: 10, res: &data); |
465 | if (ret) |
466 | return ret; |
467 | if (data >= IOPRIO_NR_LEVELS || data < 0) |
468 | return -EINVAL; |
469 | |
470 | cprc->ckpt_thread_ioprio = IOPRIO_PRIO_VALUE(class, data); |
471 | if (test_opt(sbi, MERGE_CHECKPOINT)) { |
472 | ret = set_task_ioprio(task: cprc->f2fs_issue_ckpt, |
473 | ioprio: cprc->ckpt_thread_ioprio); |
474 | if (ret) |
475 | return ret; |
476 | } |
477 | |
478 | return count; |
479 | } |
480 | |
481 | ui = (unsigned int *)(ptr + a->offset); |
482 | |
483 | ret = kstrtoul(s: skip_spaces(buf), base: 0, res: &t); |
484 | if (ret < 0) |
485 | return ret; |
486 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
487 | if (a->struct_type == FAULT_INFO_TYPE && t >= BIT(FAULT_MAX)) |
488 | return -EINVAL; |
489 | if (a->struct_type == FAULT_INFO_RATE && t >= UINT_MAX) |
490 | return -EINVAL; |
491 | #endif |
492 | if (a->struct_type == RESERVED_BLOCKS) { |
493 | spin_lock(lock: &sbi->stat_lock); |
494 | if (t > (unsigned long)(sbi->user_block_count - |
495 | F2FS_OPTION(sbi).root_reserved_blocks - |
496 | SEGS_TO_BLKS(sbi, |
497 | SM_I(sbi)->additional_reserved_segments))) { |
498 | spin_unlock(lock: &sbi->stat_lock); |
499 | return -EINVAL; |
500 | } |
501 | *ui = t; |
502 | sbi->current_reserved_blocks = min(sbi->reserved_blocks, |
503 | sbi->user_block_count - valid_user_blocks(sbi)); |
504 | spin_unlock(lock: &sbi->stat_lock); |
505 | return count; |
506 | } |
507 | |
508 | if (!strcmp(a->attr.name, "discard_io_aware_gran" )) { |
509 | if (t > MAX_PLIST_NUM) |
510 | return -EINVAL; |
511 | if (!f2fs_block_unit_discard(sbi)) |
512 | return -EINVAL; |
513 | if (t == *ui) |
514 | return count; |
515 | *ui = t; |
516 | return count; |
517 | } |
518 | |
519 | if (!strcmp(a->attr.name, "discard_granularity" )) { |
520 | if (t == 0 || t > MAX_PLIST_NUM) |
521 | return -EINVAL; |
522 | if (!f2fs_block_unit_discard(sbi)) |
523 | return -EINVAL; |
524 | if (t == *ui) |
525 | return count; |
526 | *ui = t; |
527 | return count; |
528 | } |
529 | |
530 | if (!strcmp(a->attr.name, "max_ordered_discard" )) { |
531 | if (t == 0 || t > MAX_PLIST_NUM) |
532 | return -EINVAL; |
533 | if (!f2fs_block_unit_discard(sbi)) |
534 | return -EINVAL; |
535 | *ui = t; |
536 | return count; |
537 | } |
538 | |
539 | if (!strcmp(a->attr.name, "discard_urgent_util" )) { |
540 | if (t > 100) |
541 | return -EINVAL; |
542 | *ui = t; |
543 | return count; |
544 | } |
545 | |
546 | if (!strcmp(a->attr.name, "discard_io_aware" )) { |
547 | if (t >= DPOLICY_IO_AWARE_MAX) |
548 | return -EINVAL; |
549 | *ui = t; |
550 | return count; |
551 | } |
552 | |
553 | if (!strcmp(a->attr.name, "migration_granularity" )) { |
554 | if (t == 0 || t > SEGS_PER_SEC(sbi)) |
555 | return -EINVAL; |
556 | } |
557 | |
558 | if (!strcmp(a->attr.name, "gc_urgent" )) { |
559 | if (t == 0) { |
560 | sbi->gc_mode = GC_NORMAL; |
561 | } else if (t == 1) { |
562 | sbi->gc_mode = GC_URGENT_HIGH; |
563 | if (sbi->gc_thread) { |
564 | sbi->gc_thread->gc_wake = true; |
565 | wake_up_interruptible_all( |
566 | &sbi->gc_thread->gc_wait_queue_head); |
567 | wake_up_discard_thread(sbi, force: true); |
568 | } |
569 | } else if (t == 2) { |
570 | sbi->gc_mode = GC_URGENT_LOW; |
571 | } else if (t == 3) { |
572 | sbi->gc_mode = GC_URGENT_MID; |
573 | if (sbi->gc_thread) { |
574 | sbi->gc_thread->gc_wake = true; |
575 | wake_up_interruptible_all( |
576 | &sbi->gc_thread->gc_wait_queue_head); |
577 | } |
578 | } else { |
579 | return -EINVAL; |
580 | } |
581 | return count; |
582 | } |
583 | if (!strcmp(a->attr.name, "gc_idle" )) { |
584 | if (t == GC_IDLE_CB) { |
585 | sbi->gc_mode = GC_IDLE_CB; |
586 | } else if (t == GC_IDLE_GREEDY) { |
587 | sbi->gc_mode = GC_IDLE_GREEDY; |
588 | } else if (t == GC_IDLE_AT) { |
589 | if (!sbi->am.atgc_enabled) |
590 | return -EINVAL; |
591 | sbi->gc_mode = GC_IDLE_AT; |
592 | } else { |
593 | sbi->gc_mode = GC_NORMAL; |
594 | } |
595 | return count; |
596 | } |
597 | |
598 | if (!strcmp(a->attr.name, "gc_remaining_trials" )) { |
599 | spin_lock(lock: &sbi->gc_remaining_trials_lock); |
600 | sbi->gc_remaining_trials = t; |
601 | spin_unlock(lock: &sbi->gc_remaining_trials_lock); |
602 | |
603 | return count; |
604 | } |
605 | |
606 | #ifdef CONFIG_F2FS_IOSTAT |
607 | if (!strcmp(a->attr.name, "iostat_enable" )) { |
608 | sbi->iostat_enable = !!t; |
609 | if (!sbi->iostat_enable) |
610 | f2fs_reset_iostat(sbi); |
611 | return count; |
612 | } |
613 | |
614 | if (!strcmp(a->attr.name, "iostat_period_ms" )) { |
615 | if (t < MIN_IOSTAT_PERIOD_MS || t > MAX_IOSTAT_PERIOD_MS) |
616 | return -EINVAL; |
617 | spin_lock_irq(lock: &sbi->iostat_lock); |
618 | sbi->iostat_period_ms = (unsigned int)t; |
619 | spin_unlock_irq(lock: &sbi->iostat_lock); |
620 | return count; |
621 | } |
622 | #endif |
623 | |
624 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
625 | if (!strcmp(a->attr.name, "compr_written_block" ) || |
626 | !strcmp(a->attr.name, "compr_saved_block" )) { |
627 | if (t != 0) |
628 | return -EINVAL; |
629 | sbi->compr_written_block = 0; |
630 | sbi->compr_saved_block = 0; |
631 | return count; |
632 | } |
633 | |
634 | if (!strcmp(a->attr.name, "compr_new_inode" )) { |
635 | if (t != 0) |
636 | return -EINVAL; |
637 | sbi->compr_new_inode = 0; |
638 | return count; |
639 | } |
640 | |
641 | if (!strcmp(a->attr.name, "compress_percent" )) { |
642 | if (t == 0 || t > 100) |
643 | return -EINVAL; |
644 | *ui = t; |
645 | return count; |
646 | } |
647 | |
648 | if (!strcmp(a->attr.name, "compress_watermark" )) { |
649 | if (t == 0 || t > 100) |
650 | return -EINVAL; |
651 | *ui = t; |
652 | return count; |
653 | } |
654 | #endif |
655 | |
656 | if (!strcmp(a->attr.name, "atgc_candidate_ratio" )) { |
657 | if (t > 100) |
658 | return -EINVAL; |
659 | sbi->am.candidate_ratio = t; |
660 | return count; |
661 | } |
662 | |
663 | if (!strcmp(a->attr.name, "atgc_age_weight" )) { |
664 | if (t > 100) |
665 | return -EINVAL; |
666 | sbi->am.age_weight = t; |
667 | return count; |
668 | } |
669 | |
670 | if (!strcmp(a->attr.name, "gc_segment_mode" )) { |
671 | if (t < MAX_GC_MODE) |
672 | sbi->gc_segment_mode = t; |
673 | else |
674 | return -EINVAL; |
675 | return count; |
676 | } |
677 | |
678 | if (!strcmp(a->attr.name, "gc_reclaimed_segments" )) { |
679 | if (t != 0) |
680 | return -EINVAL; |
681 | sbi->gc_reclaimed_segs[sbi->gc_segment_mode] = 0; |
682 | return count; |
683 | } |
684 | |
685 | if (!strcmp(a->attr.name, "seq_file_ra_mul" )) { |
686 | if (t >= MIN_RA_MUL && t <= MAX_RA_MUL) |
687 | sbi->seq_file_ra_mul = t; |
688 | else |
689 | return -EINVAL; |
690 | return count; |
691 | } |
692 | |
693 | if (!strcmp(a->attr.name, "max_fragment_chunk" )) { |
694 | if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE) |
695 | sbi->max_fragment_chunk = t; |
696 | else |
697 | return -EINVAL; |
698 | return count; |
699 | } |
700 | |
701 | if (!strcmp(a->attr.name, "max_fragment_hole" )) { |
702 | if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE) |
703 | sbi->max_fragment_hole = t; |
704 | else |
705 | return -EINVAL; |
706 | return count; |
707 | } |
708 | |
709 | if (!strcmp(a->attr.name, "peak_atomic_write" )) { |
710 | if (t != 0) |
711 | return -EINVAL; |
712 | sbi->peak_atomic_write = 0; |
713 | return count; |
714 | } |
715 | |
716 | if (!strcmp(a->attr.name, "committed_atomic_block" )) { |
717 | if (t != 0) |
718 | return -EINVAL; |
719 | sbi->committed_atomic_block = 0; |
720 | return count; |
721 | } |
722 | |
723 | if (!strcmp(a->attr.name, "revoked_atomic_block" )) { |
724 | if (t != 0) |
725 | return -EINVAL; |
726 | sbi->revoked_atomic_block = 0; |
727 | return count; |
728 | } |
729 | |
730 | if (!strcmp(a->attr.name, "readdir_ra" )) { |
731 | sbi->readdir_ra = !!t; |
732 | return count; |
733 | } |
734 | |
735 | if (!strcmp(a->attr.name, "hot_data_age_threshold" )) { |
736 | if (t == 0 || t >= sbi->warm_data_age_threshold) |
737 | return -EINVAL; |
738 | if (t == *ui) |
739 | return count; |
740 | *ui = (unsigned int)t; |
741 | return count; |
742 | } |
743 | |
744 | if (!strcmp(a->attr.name, "warm_data_age_threshold" )) { |
745 | if (t <= sbi->hot_data_age_threshold) |
746 | return -EINVAL; |
747 | if (t == *ui) |
748 | return count; |
749 | *ui = (unsigned int)t; |
750 | return count; |
751 | } |
752 | |
753 | if (!strcmp(a->attr.name, "last_age_weight" )) { |
754 | if (t > 100) |
755 | return -EINVAL; |
756 | if (t == *ui) |
757 | return count; |
758 | *ui = (unsigned int)t; |
759 | return count; |
760 | } |
761 | |
762 | if (!strcmp(a->attr.name, "ipu_policy" )) { |
763 | if (t >= BIT(F2FS_IPU_MAX)) |
764 | return -EINVAL; |
765 | if (t && f2fs_lfs_mode(sbi)) |
766 | return -EINVAL; |
767 | SM_I(sbi)->ipu_policy = (unsigned int)t; |
768 | return count; |
769 | } |
770 | |
771 | if (!strcmp(a->attr.name, "dir_level" )) { |
772 | if (t > MAX_DIR_HASH_DEPTH) |
773 | return -EINVAL; |
774 | sbi->dir_level = t; |
775 | return count; |
776 | } |
777 | |
778 | *ui = (unsigned int)t; |
779 | |
780 | return count; |
781 | } |
782 | |
783 | static ssize_t f2fs_sbi_store(struct f2fs_attr *a, |
784 | struct f2fs_sb_info *sbi, |
785 | const char *buf, size_t count) |
786 | { |
787 | ssize_t ret; |
788 | bool gc_entry = (!strcmp(a->attr.name, "gc_urgent" ) || |
789 | a->struct_type == GC_THREAD); |
790 | |
791 | if (gc_entry) { |
792 | if (!down_read_trylock(sem: &sbi->sb->s_umount)) |
793 | return -EAGAIN; |
794 | } |
795 | ret = __sbi_store(a, sbi, buf, count); |
796 | if (gc_entry) |
797 | up_read(sem: &sbi->sb->s_umount); |
798 | |
799 | return ret; |
800 | } |
801 | |
802 | static ssize_t f2fs_attr_show(struct kobject *kobj, |
803 | struct attribute *attr, char *buf) |
804 | { |
805 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
806 | s_kobj); |
807 | struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
808 | |
809 | return a->show ? a->show(a, sbi, buf) : 0; |
810 | } |
811 | |
812 | static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr, |
813 | const char *buf, size_t len) |
814 | { |
815 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
816 | s_kobj); |
817 | struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
818 | |
819 | return a->store ? a->store(a, sbi, buf, len) : 0; |
820 | } |
821 | |
822 | static void f2fs_sb_release(struct kobject *kobj) |
823 | { |
824 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
825 | s_kobj); |
826 | complete(&sbi->s_kobj_unregister); |
827 | } |
828 | |
829 | /* |
830 | * Note that there are three feature list entries: |
831 | * 1) /sys/fs/f2fs/features |
832 | * : shows runtime features supported by in-kernel f2fs along with Kconfig. |
833 | * - ref. F2FS_FEATURE_RO_ATTR() |
834 | * |
835 | * 2) /sys/fs/f2fs/$s_id/features <deprecated> |
836 | * : shows on-disk features enabled by mkfs.f2fs, used for old kernels. This |
837 | * won't add new feature anymore, and thus, users should check entries in 3) |
838 | * instead of this 2). |
839 | * |
840 | * 3) /sys/fs/f2fs/$s_id/feature_list |
841 | * : shows on-disk features enabled by mkfs.f2fs per instance, which follows |
842 | * sysfs entry rule where each entry should expose single value. |
843 | * This list covers old feature list provided by 2) and beyond. Therefore, |
844 | * please add new on-disk feature in this list only. |
845 | * - ref. F2FS_SB_FEATURE_RO_ATTR() |
846 | */ |
847 | static ssize_t f2fs_feature_show(struct f2fs_attr *a, |
848 | struct f2fs_sb_info *sbi, char *buf) |
849 | { |
850 | return sysfs_emit(buf, fmt: "supported\n" ); |
851 | } |
852 | |
853 | #define F2FS_FEATURE_RO_ATTR(_name) \ |
854 | static struct f2fs_attr f2fs_attr_##_name = { \ |
855 | .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
856 | .show = f2fs_feature_show, \ |
857 | } |
858 | |
859 | static ssize_t f2fs_sb_feature_show(struct f2fs_attr *a, |
860 | struct f2fs_sb_info *sbi, char *buf) |
861 | { |
862 | if (F2FS_HAS_FEATURE(sbi, a->id)) |
863 | return sysfs_emit(buf, fmt: "supported\n" ); |
864 | return sysfs_emit(buf, fmt: "unsupported\n" ); |
865 | } |
866 | |
867 | #define F2FS_SB_FEATURE_RO_ATTR(_name, _feat) \ |
868 | static struct f2fs_attr f2fs_attr_sb_##_name = { \ |
869 | .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
870 | .show = f2fs_sb_feature_show, \ |
871 | .id = F2FS_FEATURE_##_feat, \ |
872 | } |
873 | |
874 | #define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ |
875 | static struct f2fs_attr f2fs_attr_##_name = { \ |
876 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
877 | .show = _show, \ |
878 | .store = _store, \ |
879 | .struct_type = _struct_type, \ |
880 | .offset = _offset \ |
881 | } |
882 | |
883 | #define F2FS_RO_ATTR(struct_type, struct_name, name, elname) \ |
884 | F2FS_ATTR_OFFSET(struct_type, name, 0444, \ |
885 | f2fs_sbi_show, NULL, \ |
886 | offsetof(struct struct_name, elname)) |
887 | |
888 | #define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \ |
889 | F2FS_ATTR_OFFSET(struct_type, name, 0644, \ |
890 | f2fs_sbi_show, f2fs_sbi_store, \ |
891 | offsetof(struct struct_name, elname)) |
892 | |
893 | #define F2FS_GENERAL_RO_ATTR(name) \ |
894 | static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) |
895 | |
896 | #ifdef CONFIG_F2FS_STAT_FS |
897 | #define STAT_INFO_RO_ATTR(name, elname) \ |
898 | F2FS_RO_ATTR(STAT_INFO, f2fs_stat_info, name, elname) |
899 | #endif |
900 | |
901 | #define GC_THREAD_RW_ATTR(name, elname) \ |
902 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, name, elname) |
903 | |
904 | #define SM_INFO_RW_ATTR(name, elname) \ |
905 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, name, elname) |
906 | |
907 | #define SM_INFO_GENERAL_RW_ATTR(elname) \ |
908 | SM_INFO_RW_ATTR(elname, elname) |
909 | |
910 | #define DCC_INFO_RW_ATTR(name, elname) \ |
911 | F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, name, elname) |
912 | |
913 | #define DCC_INFO_GENERAL_RW_ATTR(elname) \ |
914 | DCC_INFO_RW_ATTR(elname, elname) |
915 | |
916 | #define NM_INFO_RW_ATTR(name, elname) \ |
917 | F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, name, elname) |
918 | |
919 | #define NM_INFO_GENERAL_RW_ATTR(elname) \ |
920 | NM_INFO_RW_ATTR(elname, elname) |
921 | |
922 | #define F2FS_SBI_RW_ATTR(name, elname) \ |
923 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, name, elname) |
924 | |
925 | #define F2FS_SBI_GENERAL_RW_ATTR(elname) \ |
926 | F2FS_SBI_RW_ATTR(elname, elname) |
927 | |
928 | #define F2FS_SBI_GENERAL_RO_ATTR(elname) \ |
929 | F2FS_RO_ATTR(F2FS_SBI, f2fs_sb_info, elname, elname) |
930 | |
931 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
932 | #define FAULT_INFO_GENERAL_RW_ATTR(type, elname) \ |
933 | F2FS_RW_ATTR(type, f2fs_fault_info, elname, elname) |
934 | #endif |
935 | |
936 | #define RESERVED_BLOCKS_GENERAL_RW_ATTR(elname) \ |
937 | F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, elname, elname) |
938 | |
939 | #define CPRC_INFO_GENERAL_RW_ATTR(elname) \ |
940 | F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, elname, elname) |
941 | |
942 | #define ATGC_INFO_RW_ATTR(name, elname) \ |
943 | F2FS_RW_ATTR(ATGC_INFO, atgc_management, name, elname) |
944 | |
945 | /* GC_THREAD ATTR */ |
946 | GC_THREAD_RW_ATTR(gc_urgent_sleep_time, urgent_sleep_time); |
947 | GC_THREAD_RW_ATTR(gc_min_sleep_time, min_sleep_time); |
948 | GC_THREAD_RW_ATTR(gc_max_sleep_time, max_sleep_time); |
949 | GC_THREAD_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); |
950 | |
951 | /* SM_INFO ATTR */ |
952 | SM_INFO_RW_ATTR(reclaim_segments, rec_prefree_segments); |
953 | SM_INFO_GENERAL_RW_ATTR(ipu_policy); |
954 | SM_INFO_GENERAL_RW_ATTR(min_ipu_util); |
955 | SM_INFO_GENERAL_RW_ATTR(min_fsync_blocks); |
956 | SM_INFO_GENERAL_RW_ATTR(min_seq_blocks); |
957 | SM_INFO_GENERAL_RW_ATTR(min_hot_blocks); |
958 | SM_INFO_GENERAL_RW_ATTR(min_ssr_sections); |
959 | |
960 | /* DCC_INFO ATTR */ |
961 | DCC_INFO_RW_ATTR(max_small_discards, max_discards); |
962 | DCC_INFO_GENERAL_RW_ATTR(max_discard_request); |
963 | DCC_INFO_GENERAL_RW_ATTR(min_discard_issue_time); |
964 | DCC_INFO_GENERAL_RW_ATTR(mid_discard_issue_time); |
965 | DCC_INFO_GENERAL_RW_ATTR(max_discard_issue_time); |
966 | DCC_INFO_GENERAL_RW_ATTR(discard_io_aware_gran); |
967 | DCC_INFO_GENERAL_RW_ATTR(discard_urgent_util); |
968 | DCC_INFO_GENERAL_RW_ATTR(discard_granularity); |
969 | DCC_INFO_GENERAL_RW_ATTR(max_ordered_discard); |
970 | DCC_INFO_GENERAL_RW_ATTR(discard_io_aware); |
971 | |
972 | /* NM_INFO ATTR */ |
973 | NM_INFO_RW_ATTR(max_roll_forward_node_blocks, max_rf_node_blocks); |
974 | NM_INFO_GENERAL_RW_ATTR(ram_thresh); |
975 | NM_INFO_GENERAL_RW_ATTR(ra_nid_pages); |
976 | NM_INFO_GENERAL_RW_ATTR(dirty_nats_ratio); |
977 | |
978 | /* F2FS_SBI ATTR */ |
979 | F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); |
980 | F2FS_SBI_RW_ATTR(gc_idle, gc_mode); |
981 | F2FS_SBI_RW_ATTR(gc_urgent, gc_mode); |
982 | F2FS_SBI_RW_ATTR(cp_interval, interval_time[CP_TIME]); |
983 | F2FS_SBI_RW_ATTR(idle_interval, interval_time[REQ_TIME]); |
984 | F2FS_SBI_RW_ATTR(discard_idle_interval, interval_time[DISCARD_TIME]); |
985 | F2FS_SBI_RW_ATTR(gc_idle_interval, interval_time[GC_TIME]); |
986 | F2FS_SBI_RW_ATTR(umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]); |
987 | F2FS_SBI_RW_ATTR(gc_pin_file_thresh, gc_pin_file_threshold); |
988 | F2FS_SBI_RW_ATTR(gc_reclaimed_segments, gc_reclaimed_segs); |
989 | F2FS_SBI_GENERAL_RW_ATTR(max_victim_search); |
990 | F2FS_SBI_GENERAL_RW_ATTR(migration_granularity); |
991 | F2FS_SBI_GENERAL_RW_ATTR(dir_level); |
992 | #ifdef CONFIG_F2FS_IOSTAT |
993 | F2FS_SBI_GENERAL_RW_ATTR(iostat_enable); |
994 | F2FS_SBI_GENERAL_RW_ATTR(iostat_period_ms); |
995 | #endif |
996 | F2FS_SBI_GENERAL_RW_ATTR(readdir_ra); |
997 | F2FS_SBI_GENERAL_RW_ATTR(max_io_bytes); |
998 | F2FS_SBI_GENERAL_RW_ATTR(data_io_flag); |
999 | F2FS_SBI_GENERAL_RW_ATTR(node_io_flag); |
1000 | F2FS_SBI_GENERAL_RW_ATTR(gc_remaining_trials); |
1001 | F2FS_SBI_GENERAL_RW_ATTR(seq_file_ra_mul); |
1002 | F2FS_SBI_GENERAL_RW_ATTR(gc_segment_mode); |
1003 | F2FS_SBI_GENERAL_RW_ATTR(max_fragment_chunk); |
1004 | F2FS_SBI_GENERAL_RW_ATTR(max_fragment_hole); |
1005 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
1006 | F2FS_SBI_GENERAL_RW_ATTR(compr_written_block); |
1007 | F2FS_SBI_GENERAL_RW_ATTR(compr_saved_block); |
1008 | F2FS_SBI_GENERAL_RW_ATTR(compr_new_inode); |
1009 | F2FS_SBI_GENERAL_RW_ATTR(compress_percent); |
1010 | F2FS_SBI_GENERAL_RW_ATTR(compress_watermark); |
1011 | #endif |
1012 | /* atomic write */ |
1013 | F2FS_SBI_GENERAL_RO_ATTR(current_atomic_write); |
1014 | F2FS_SBI_GENERAL_RW_ATTR(peak_atomic_write); |
1015 | F2FS_SBI_GENERAL_RW_ATTR(committed_atomic_block); |
1016 | F2FS_SBI_GENERAL_RW_ATTR(revoked_atomic_block); |
1017 | /* block age extent cache */ |
1018 | F2FS_SBI_GENERAL_RW_ATTR(hot_data_age_threshold); |
1019 | F2FS_SBI_GENERAL_RW_ATTR(warm_data_age_threshold); |
1020 | F2FS_SBI_GENERAL_RW_ATTR(last_age_weight); |
1021 | #ifdef CONFIG_BLK_DEV_ZONED |
1022 | F2FS_SBI_GENERAL_RO_ATTR(unusable_blocks_per_sec); |
1023 | #endif |
1024 | |
1025 | /* STAT_INFO ATTR */ |
1026 | #ifdef CONFIG_F2FS_STAT_FS |
1027 | STAT_INFO_RO_ATTR(cp_foreground_calls, cp_call_count[FOREGROUND]); |
1028 | STAT_INFO_RO_ATTR(cp_background_calls, cp_call_count[BACKGROUND]); |
1029 | STAT_INFO_RO_ATTR(gc_foreground_calls, gc_call_count[FOREGROUND]); |
1030 | STAT_INFO_RO_ATTR(gc_background_calls, gc_call_count[BACKGROUND]); |
1031 | #endif |
1032 | |
1033 | /* FAULT_INFO ATTR */ |
1034 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
1035 | FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_RATE, inject_rate); |
1036 | FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_TYPE, inject_type); |
1037 | #endif |
1038 | |
1039 | /* RESERVED_BLOCKS ATTR */ |
1040 | RESERVED_BLOCKS_GENERAL_RW_ATTR(reserved_blocks); |
1041 | |
1042 | /* CPRC_INFO ATTR */ |
1043 | CPRC_INFO_GENERAL_RW_ATTR(ckpt_thread_ioprio); |
1044 | |
1045 | /* ATGC_INFO ATTR */ |
1046 | ATGC_INFO_RW_ATTR(atgc_candidate_ratio, candidate_ratio); |
1047 | ATGC_INFO_RW_ATTR(atgc_candidate_count, max_candidate_count); |
1048 | ATGC_INFO_RW_ATTR(atgc_age_weight, age_weight); |
1049 | ATGC_INFO_RW_ATTR(atgc_age_threshold, age_threshold); |
1050 | |
1051 | F2FS_GENERAL_RO_ATTR(dirty_segments); |
1052 | F2FS_GENERAL_RO_ATTR(free_segments); |
1053 | F2FS_GENERAL_RO_ATTR(ovp_segments); |
1054 | F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); |
1055 | F2FS_GENERAL_RO_ATTR(features); |
1056 | F2FS_GENERAL_RO_ATTR(current_reserved_blocks); |
1057 | F2FS_GENERAL_RO_ATTR(unusable); |
1058 | F2FS_GENERAL_RO_ATTR(encoding); |
1059 | F2FS_GENERAL_RO_ATTR(mounted_time_sec); |
1060 | F2FS_GENERAL_RO_ATTR(main_blkaddr); |
1061 | F2FS_GENERAL_RO_ATTR(pending_discard); |
1062 | F2FS_GENERAL_RO_ATTR(gc_mode); |
1063 | #ifdef CONFIG_F2FS_STAT_FS |
1064 | F2FS_GENERAL_RO_ATTR(moved_blocks_background); |
1065 | F2FS_GENERAL_RO_ATTR(moved_blocks_foreground); |
1066 | F2FS_GENERAL_RO_ATTR(avg_vblocks); |
1067 | #endif |
1068 | |
1069 | #ifdef CONFIG_FS_ENCRYPTION |
1070 | F2FS_FEATURE_RO_ATTR(encryption); |
1071 | F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2); |
1072 | #if IS_ENABLED(CONFIG_UNICODE) |
1073 | F2FS_FEATURE_RO_ATTR(encrypted_casefold); |
1074 | #endif |
1075 | #endif /* CONFIG_FS_ENCRYPTION */ |
1076 | #ifdef CONFIG_BLK_DEV_ZONED |
1077 | F2FS_FEATURE_RO_ATTR(block_zoned); |
1078 | #endif |
1079 | F2FS_FEATURE_RO_ATTR(atomic_write); |
1080 | F2FS_FEATURE_RO_ATTR(extra_attr); |
1081 | F2FS_FEATURE_RO_ATTR(project_quota); |
1082 | F2FS_FEATURE_RO_ATTR(inode_checksum); |
1083 | F2FS_FEATURE_RO_ATTR(flexible_inline_xattr); |
1084 | F2FS_FEATURE_RO_ATTR(quota_ino); |
1085 | F2FS_FEATURE_RO_ATTR(inode_crtime); |
1086 | F2FS_FEATURE_RO_ATTR(lost_found); |
1087 | #ifdef CONFIG_FS_VERITY |
1088 | F2FS_FEATURE_RO_ATTR(verity); |
1089 | #endif |
1090 | F2FS_FEATURE_RO_ATTR(sb_checksum); |
1091 | #if IS_ENABLED(CONFIG_UNICODE) |
1092 | F2FS_FEATURE_RO_ATTR(casefold); |
1093 | #endif |
1094 | F2FS_FEATURE_RO_ATTR(readonly); |
1095 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
1096 | F2FS_FEATURE_RO_ATTR(compression); |
1097 | #endif |
1098 | F2FS_FEATURE_RO_ATTR(pin_file); |
1099 | |
1100 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) |
1101 | static struct attribute *f2fs_attrs[] = { |
1102 | ATTR_LIST(gc_urgent_sleep_time), |
1103 | ATTR_LIST(gc_min_sleep_time), |
1104 | ATTR_LIST(gc_max_sleep_time), |
1105 | ATTR_LIST(gc_no_gc_sleep_time), |
1106 | ATTR_LIST(gc_idle), |
1107 | ATTR_LIST(gc_urgent), |
1108 | ATTR_LIST(reclaim_segments), |
1109 | ATTR_LIST(main_blkaddr), |
1110 | ATTR_LIST(max_small_discards), |
1111 | ATTR_LIST(max_discard_request), |
1112 | ATTR_LIST(min_discard_issue_time), |
1113 | ATTR_LIST(mid_discard_issue_time), |
1114 | ATTR_LIST(max_discard_issue_time), |
1115 | ATTR_LIST(discard_io_aware_gran), |
1116 | ATTR_LIST(discard_urgent_util), |
1117 | ATTR_LIST(discard_granularity), |
1118 | ATTR_LIST(max_ordered_discard), |
1119 | ATTR_LIST(discard_io_aware), |
1120 | ATTR_LIST(pending_discard), |
1121 | ATTR_LIST(gc_mode), |
1122 | ATTR_LIST(ipu_policy), |
1123 | ATTR_LIST(min_ipu_util), |
1124 | ATTR_LIST(min_fsync_blocks), |
1125 | ATTR_LIST(min_seq_blocks), |
1126 | ATTR_LIST(min_hot_blocks), |
1127 | ATTR_LIST(min_ssr_sections), |
1128 | ATTR_LIST(max_victim_search), |
1129 | ATTR_LIST(migration_granularity), |
1130 | ATTR_LIST(dir_level), |
1131 | ATTR_LIST(ram_thresh), |
1132 | ATTR_LIST(ra_nid_pages), |
1133 | ATTR_LIST(dirty_nats_ratio), |
1134 | ATTR_LIST(max_roll_forward_node_blocks), |
1135 | ATTR_LIST(cp_interval), |
1136 | ATTR_LIST(idle_interval), |
1137 | ATTR_LIST(discard_idle_interval), |
1138 | ATTR_LIST(gc_idle_interval), |
1139 | ATTR_LIST(umount_discard_timeout), |
1140 | #ifdef CONFIG_F2FS_IOSTAT |
1141 | ATTR_LIST(iostat_enable), |
1142 | ATTR_LIST(iostat_period_ms), |
1143 | #endif |
1144 | ATTR_LIST(readdir_ra), |
1145 | ATTR_LIST(max_io_bytes), |
1146 | ATTR_LIST(gc_pin_file_thresh), |
1147 | ATTR_LIST(extension_list), |
1148 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
1149 | ATTR_LIST(inject_rate), |
1150 | ATTR_LIST(inject_type), |
1151 | #endif |
1152 | ATTR_LIST(data_io_flag), |
1153 | ATTR_LIST(node_io_flag), |
1154 | ATTR_LIST(gc_remaining_trials), |
1155 | ATTR_LIST(ckpt_thread_ioprio), |
1156 | ATTR_LIST(dirty_segments), |
1157 | ATTR_LIST(free_segments), |
1158 | ATTR_LIST(ovp_segments), |
1159 | ATTR_LIST(unusable), |
1160 | ATTR_LIST(lifetime_write_kbytes), |
1161 | ATTR_LIST(features), |
1162 | ATTR_LIST(reserved_blocks), |
1163 | ATTR_LIST(current_reserved_blocks), |
1164 | ATTR_LIST(encoding), |
1165 | ATTR_LIST(mounted_time_sec), |
1166 | #ifdef CONFIG_F2FS_STAT_FS |
1167 | ATTR_LIST(cp_foreground_calls), |
1168 | ATTR_LIST(cp_background_calls), |
1169 | ATTR_LIST(gc_foreground_calls), |
1170 | ATTR_LIST(gc_background_calls), |
1171 | ATTR_LIST(moved_blocks_foreground), |
1172 | ATTR_LIST(moved_blocks_background), |
1173 | ATTR_LIST(avg_vblocks), |
1174 | #endif |
1175 | #ifdef CONFIG_BLK_DEV_ZONED |
1176 | ATTR_LIST(unusable_blocks_per_sec), |
1177 | #endif |
1178 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
1179 | ATTR_LIST(compr_written_block), |
1180 | ATTR_LIST(compr_saved_block), |
1181 | ATTR_LIST(compr_new_inode), |
1182 | ATTR_LIST(compress_percent), |
1183 | ATTR_LIST(compress_watermark), |
1184 | #endif |
1185 | /* For ATGC */ |
1186 | ATTR_LIST(atgc_candidate_ratio), |
1187 | ATTR_LIST(atgc_candidate_count), |
1188 | ATTR_LIST(atgc_age_weight), |
1189 | ATTR_LIST(atgc_age_threshold), |
1190 | ATTR_LIST(seq_file_ra_mul), |
1191 | ATTR_LIST(gc_segment_mode), |
1192 | ATTR_LIST(gc_reclaimed_segments), |
1193 | ATTR_LIST(max_fragment_chunk), |
1194 | ATTR_LIST(max_fragment_hole), |
1195 | ATTR_LIST(current_atomic_write), |
1196 | ATTR_LIST(peak_atomic_write), |
1197 | ATTR_LIST(committed_atomic_block), |
1198 | ATTR_LIST(revoked_atomic_block), |
1199 | ATTR_LIST(hot_data_age_threshold), |
1200 | ATTR_LIST(warm_data_age_threshold), |
1201 | ATTR_LIST(last_age_weight), |
1202 | NULL, |
1203 | }; |
1204 | ATTRIBUTE_GROUPS(f2fs); |
1205 | |
1206 | static struct attribute *f2fs_feat_attrs[] = { |
1207 | #ifdef CONFIG_FS_ENCRYPTION |
1208 | ATTR_LIST(encryption), |
1209 | ATTR_LIST(test_dummy_encryption_v2), |
1210 | #if IS_ENABLED(CONFIG_UNICODE) |
1211 | ATTR_LIST(encrypted_casefold), |
1212 | #endif |
1213 | #endif /* CONFIG_FS_ENCRYPTION */ |
1214 | #ifdef CONFIG_BLK_DEV_ZONED |
1215 | ATTR_LIST(block_zoned), |
1216 | #endif |
1217 | ATTR_LIST(atomic_write), |
1218 | ATTR_LIST(extra_attr), |
1219 | ATTR_LIST(project_quota), |
1220 | ATTR_LIST(inode_checksum), |
1221 | ATTR_LIST(flexible_inline_xattr), |
1222 | ATTR_LIST(quota_ino), |
1223 | ATTR_LIST(inode_crtime), |
1224 | ATTR_LIST(lost_found), |
1225 | #ifdef CONFIG_FS_VERITY |
1226 | ATTR_LIST(verity), |
1227 | #endif |
1228 | ATTR_LIST(sb_checksum), |
1229 | #if IS_ENABLED(CONFIG_UNICODE) |
1230 | ATTR_LIST(casefold), |
1231 | #endif |
1232 | ATTR_LIST(readonly), |
1233 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
1234 | ATTR_LIST(compression), |
1235 | #endif |
1236 | ATTR_LIST(pin_file), |
1237 | NULL, |
1238 | }; |
1239 | ATTRIBUTE_GROUPS(f2fs_feat); |
1240 | |
1241 | F2FS_GENERAL_RO_ATTR(sb_status); |
1242 | F2FS_GENERAL_RO_ATTR(cp_status); |
1243 | F2FS_GENERAL_RO_ATTR(issued_discard); |
1244 | F2FS_GENERAL_RO_ATTR(queued_discard); |
1245 | F2FS_GENERAL_RO_ATTR(undiscard_blks); |
1246 | |
1247 | static struct attribute *f2fs_stat_attrs[] = { |
1248 | ATTR_LIST(sb_status), |
1249 | ATTR_LIST(cp_status), |
1250 | ATTR_LIST(issued_discard), |
1251 | ATTR_LIST(queued_discard), |
1252 | ATTR_LIST(undiscard_blks), |
1253 | NULL, |
1254 | }; |
1255 | ATTRIBUTE_GROUPS(f2fs_stat); |
1256 | |
1257 | F2FS_SB_FEATURE_RO_ATTR(encryption, ENCRYPT); |
1258 | F2FS_SB_FEATURE_RO_ATTR(block_zoned, BLKZONED); |
1259 | F2FS_SB_FEATURE_RO_ATTR(extra_attr, EXTRA_ATTR); |
1260 | F2FS_SB_FEATURE_RO_ATTR(project_quota, PRJQUOTA); |
1261 | F2FS_SB_FEATURE_RO_ATTR(inode_checksum, INODE_CHKSUM); |
1262 | F2FS_SB_FEATURE_RO_ATTR(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); |
1263 | F2FS_SB_FEATURE_RO_ATTR(quota_ino, QUOTA_INO); |
1264 | F2FS_SB_FEATURE_RO_ATTR(inode_crtime, INODE_CRTIME); |
1265 | F2FS_SB_FEATURE_RO_ATTR(lost_found, LOST_FOUND); |
1266 | F2FS_SB_FEATURE_RO_ATTR(verity, VERITY); |
1267 | F2FS_SB_FEATURE_RO_ATTR(sb_checksum, SB_CHKSUM); |
1268 | F2FS_SB_FEATURE_RO_ATTR(casefold, CASEFOLD); |
1269 | F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION); |
1270 | F2FS_SB_FEATURE_RO_ATTR(readonly, RO); |
1271 | |
1272 | static struct attribute *f2fs_sb_feat_attrs[] = { |
1273 | ATTR_LIST(sb_encryption), |
1274 | ATTR_LIST(sb_block_zoned), |
1275 | ATTR_LIST(sb_extra_attr), |
1276 | ATTR_LIST(sb_project_quota), |
1277 | ATTR_LIST(sb_inode_checksum), |
1278 | ATTR_LIST(sb_flexible_inline_xattr), |
1279 | ATTR_LIST(sb_quota_ino), |
1280 | ATTR_LIST(sb_inode_crtime), |
1281 | ATTR_LIST(sb_lost_found), |
1282 | ATTR_LIST(sb_verity), |
1283 | ATTR_LIST(sb_sb_checksum), |
1284 | ATTR_LIST(sb_casefold), |
1285 | ATTR_LIST(sb_compression), |
1286 | ATTR_LIST(sb_readonly), |
1287 | NULL, |
1288 | }; |
1289 | ATTRIBUTE_GROUPS(f2fs_sb_feat); |
1290 | |
1291 | static const struct sysfs_ops f2fs_attr_ops = { |
1292 | .show = f2fs_attr_show, |
1293 | .store = f2fs_attr_store, |
1294 | }; |
1295 | |
1296 | static const struct kobj_type f2fs_sb_ktype = { |
1297 | .default_groups = f2fs_groups, |
1298 | .sysfs_ops = &f2fs_attr_ops, |
1299 | .release = f2fs_sb_release, |
1300 | }; |
1301 | |
1302 | static const struct kobj_type f2fs_ktype = { |
1303 | .sysfs_ops = &f2fs_attr_ops, |
1304 | }; |
1305 | |
1306 | static struct kset f2fs_kset = { |
1307 | .kobj = {.ktype = &f2fs_ktype}, |
1308 | }; |
1309 | |
1310 | static const struct kobj_type f2fs_feat_ktype = { |
1311 | .default_groups = f2fs_feat_groups, |
1312 | .sysfs_ops = &f2fs_attr_ops, |
1313 | }; |
1314 | |
1315 | static struct kobject f2fs_feat = { |
1316 | .kset = &f2fs_kset, |
1317 | }; |
1318 | |
1319 | static ssize_t f2fs_stat_attr_show(struct kobject *kobj, |
1320 | struct attribute *attr, char *buf) |
1321 | { |
1322 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
1323 | s_stat_kobj); |
1324 | struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
1325 | |
1326 | return a->show ? a->show(a, sbi, buf) : 0; |
1327 | } |
1328 | |
1329 | static ssize_t f2fs_stat_attr_store(struct kobject *kobj, struct attribute *attr, |
1330 | const char *buf, size_t len) |
1331 | { |
1332 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
1333 | s_stat_kobj); |
1334 | struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
1335 | |
1336 | return a->store ? a->store(a, sbi, buf, len) : 0; |
1337 | } |
1338 | |
1339 | static void f2fs_stat_kobj_release(struct kobject *kobj) |
1340 | { |
1341 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
1342 | s_stat_kobj); |
1343 | complete(&sbi->s_stat_kobj_unregister); |
1344 | } |
1345 | |
1346 | static const struct sysfs_ops f2fs_stat_attr_ops = { |
1347 | .show = f2fs_stat_attr_show, |
1348 | .store = f2fs_stat_attr_store, |
1349 | }; |
1350 | |
1351 | static const struct kobj_type f2fs_stat_ktype = { |
1352 | .default_groups = f2fs_stat_groups, |
1353 | .sysfs_ops = &f2fs_stat_attr_ops, |
1354 | .release = f2fs_stat_kobj_release, |
1355 | }; |
1356 | |
1357 | static ssize_t f2fs_sb_feat_attr_show(struct kobject *kobj, |
1358 | struct attribute *attr, char *buf) |
1359 | { |
1360 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
1361 | s_feature_list_kobj); |
1362 | struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
1363 | |
1364 | return a->show ? a->show(a, sbi, buf) : 0; |
1365 | } |
1366 | |
1367 | static void f2fs_feature_list_kobj_release(struct kobject *kobj) |
1368 | { |
1369 | struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
1370 | s_feature_list_kobj); |
1371 | complete(&sbi->s_feature_list_kobj_unregister); |
1372 | } |
1373 | |
1374 | static const struct sysfs_ops f2fs_feature_list_attr_ops = { |
1375 | .show = f2fs_sb_feat_attr_show, |
1376 | }; |
1377 | |
1378 | static const struct kobj_type f2fs_feature_list_ktype = { |
1379 | .default_groups = f2fs_sb_feat_groups, |
1380 | .sysfs_ops = &f2fs_feature_list_attr_ops, |
1381 | .release = f2fs_feature_list_kobj_release, |
1382 | }; |
1383 | |
1384 | static int __maybe_unused segment_info_seq_show(struct seq_file *seq, |
1385 | void *offset) |
1386 | { |
1387 | struct super_block *sb = seq->private; |
1388 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
1389 | unsigned int total_segs = |
1390 | le32_to_cpu(sbi->raw_super->segment_count_main); |
1391 | int i; |
1392 | |
1393 | seq_puts(m: seq, s: "format: segment_type|valid_blocks\n" |
1394 | "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n" ); |
1395 | |
1396 | for (i = 0; i < total_segs; i++) { |
1397 | struct seg_entry *se = get_seg_entry(sbi, segno: i); |
1398 | |
1399 | if ((i % 10) == 0) |
1400 | seq_printf(m: seq, fmt: "%-10d" , i); |
1401 | seq_printf(m: seq, fmt: "%d|%-3u" , se->type, se->valid_blocks); |
1402 | if ((i % 10) == 9 || i == (total_segs - 1)) |
1403 | seq_putc(m: seq, c: '\n'); |
1404 | else |
1405 | seq_putc(m: seq, c: ' '); |
1406 | } |
1407 | |
1408 | return 0; |
1409 | } |
1410 | |
1411 | static int __maybe_unused segment_bits_seq_show(struct seq_file *seq, |
1412 | void *offset) |
1413 | { |
1414 | struct super_block *sb = seq->private; |
1415 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
1416 | unsigned int total_segs = |
1417 | le32_to_cpu(sbi->raw_super->segment_count_main); |
1418 | int i, j; |
1419 | |
1420 | seq_puts(m: seq, s: "format: segment_type|valid_blocks|bitmaps\n" |
1421 | "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n" ); |
1422 | |
1423 | for (i = 0; i < total_segs; i++) { |
1424 | struct seg_entry *se = get_seg_entry(sbi, segno: i); |
1425 | |
1426 | seq_printf(m: seq, fmt: "%-10d" , i); |
1427 | seq_printf(m: seq, fmt: "%d|%-3u|" , se->type, se->valid_blocks); |
1428 | for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) |
1429 | seq_printf(m: seq, fmt: " %.2x" , se->cur_valid_map[j]); |
1430 | seq_putc(m: seq, c: '\n'); |
1431 | } |
1432 | return 0; |
1433 | } |
1434 | |
1435 | static int __maybe_unused victim_bits_seq_show(struct seq_file *seq, |
1436 | void *offset) |
1437 | { |
1438 | struct super_block *sb = seq->private; |
1439 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
1440 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
1441 | int i; |
1442 | |
1443 | seq_puts(m: seq, s: "format: victim_secmap bitmaps\n" ); |
1444 | |
1445 | for (i = 0; i < MAIN_SECS(sbi); i++) { |
1446 | if ((i % 10) == 0) |
1447 | seq_printf(m: seq, fmt: "%-10d" , i); |
1448 | seq_printf(m: seq, fmt: "%d" , test_bit(i, dirty_i->victim_secmap) ? 1 : 0); |
1449 | if ((i % 10) == 9 || i == (MAIN_SECS(sbi) - 1)) |
1450 | seq_putc(m: seq, c: '\n'); |
1451 | else |
1452 | seq_putc(m: seq, c: ' '); |
1453 | } |
1454 | return 0; |
1455 | } |
1456 | |
1457 | static int __maybe_unused discard_plist_seq_show(struct seq_file *seq, |
1458 | void *offset) |
1459 | { |
1460 | struct super_block *sb = seq->private; |
1461 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
1462 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; |
1463 | int i, count; |
1464 | |
1465 | seq_puts(m: seq, s: "Discard pend list(Show diacrd_cmd count on each entry, .:not exist):\n" ); |
1466 | if (!f2fs_realtime_discard_enable(sbi)) |
1467 | return 0; |
1468 | |
1469 | if (dcc) { |
1470 | mutex_lock(&dcc->cmd_lock); |
1471 | for (i = 0; i < MAX_PLIST_NUM; i++) { |
1472 | struct list_head *pend_list; |
1473 | struct discard_cmd *dc, *tmp; |
1474 | |
1475 | if (i % 8 == 0) |
1476 | seq_printf(m: seq, fmt: " %-3d" , i); |
1477 | count = 0; |
1478 | pend_list = &dcc->pend_list[i]; |
1479 | list_for_each_entry_safe(dc, tmp, pend_list, list) |
1480 | count++; |
1481 | if (count) |
1482 | seq_printf(m: seq, fmt: " %7d" , count); |
1483 | else |
1484 | seq_puts(m: seq, s: " ." ); |
1485 | if (i % 8 == 7) |
1486 | seq_putc(m: seq, c: '\n'); |
1487 | } |
1488 | seq_putc(m: seq, c: '\n'); |
1489 | mutex_unlock(lock: &dcc->cmd_lock); |
1490 | } |
1491 | |
1492 | return 0; |
1493 | } |
1494 | |
1495 | static int __maybe_unused disk_map_seq_show(struct seq_file *seq, |
1496 | void *offset) |
1497 | { |
1498 | struct super_block *sb = seq->private; |
1499 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
1500 | int i; |
1501 | |
1502 | seq_printf(m: seq, fmt: "Address Layout : %5luB Block address (# of Segments)\n" , |
1503 | F2FS_BLKSIZE); |
1504 | seq_printf(m: seq, fmt: " SB : %12s\n" , "0/1024B" ); |
1505 | seq_printf(m: seq, fmt: " seg0_blkaddr : 0x%010x\n" , SEG0_BLKADDR(sbi)); |
1506 | seq_printf(m: seq, fmt: " Checkpoint : 0x%010x (%10d)\n" , |
1507 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr), 2); |
1508 | seq_printf(m: seq, fmt: " SIT : 0x%010x (%10d)\n" , |
1509 | SIT_I(sbi)->sit_base_addr, |
1510 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_sit)); |
1511 | seq_printf(m: seq, fmt: " NAT : 0x%010x (%10d)\n" , |
1512 | NM_I(sbi)->nat_blkaddr, |
1513 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_nat)); |
1514 | seq_printf(m: seq, fmt: " SSA : 0x%010x (%10d)\n" , |
1515 | SM_I(sbi)->ssa_blkaddr, |
1516 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_ssa)); |
1517 | seq_printf(m: seq, fmt: " Main : 0x%010x (%10d)\n" , |
1518 | SM_I(sbi)->main_blkaddr, |
1519 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_main)); |
1520 | seq_printf(m: seq, fmt: " # of Sections : %12d\n" , |
1521 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->section_count)); |
1522 | seq_printf(m: seq, fmt: " Segs/Sections : %12d\n" , |
1523 | SEGS_PER_SEC(sbi)); |
1524 | seq_printf(m: seq, fmt: " Section size : %12d MB\n" , |
1525 | SEGS_PER_SEC(sbi) << 1); |
1526 | |
1527 | if (!f2fs_is_multi_device(sbi)) |
1528 | return 0; |
1529 | |
1530 | seq_puts(m: seq, s: "\nDisk Map for multi devices:\n" ); |
1531 | for (i = 0; i < sbi->s_ndevs; i++) |
1532 | seq_printf(m: seq, fmt: "Disk:%2d (zoned=%d): 0x%010x - 0x%010x on %s\n" , |
1533 | i, bdev_is_zoned(FDEV(i).bdev), |
1534 | FDEV(i).start_blk, FDEV(i).end_blk, |
1535 | FDEV(i).path); |
1536 | return 0; |
1537 | } |
1538 | |
1539 | int __init f2fs_init_sysfs(void) |
1540 | { |
1541 | int ret; |
1542 | |
1543 | kobject_set_name(kobj: &f2fs_kset.kobj, name: "f2fs" ); |
1544 | f2fs_kset.kobj.parent = fs_kobj; |
1545 | ret = kset_register(kset: &f2fs_kset); |
1546 | if (ret) |
1547 | return ret; |
1548 | |
1549 | ret = kobject_init_and_add(kobj: &f2fs_feat, ktype: &f2fs_feat_ktype, |
1550 | NULL, fmt: "features" ); |
1551 | if (ret) |
1552 | goto put_kobject; |
1553 | |
1554 | f2fs_proc_root = proc_mkdir("fs/f2fs" , NULL); |
1555 | if (!f2fs_proc_root) { |
1556 | ret = -ENOMEM; |
1557 | goto put_kobject; |
1558 | } |
1559 | |
1560 | return 0; |
1561 | put_kobject: |
1562 | kobject_put(kobj: &f2fs_feat); |
1563 | kset_unregister(kset: &f2fs_kset); |
1564 | return ret; |
1565 | } |
1566 | |
1567 | void f2fs_exit_sysfs(void) |
1568 | { |
1569 | kobject_put(kobj: &f2fs_feat); |
1570 | kset_unregister(kset: &f2fs_kset); |
1571 | remove_proc_entry("fs/f2fs" , NULL); |
1572 | f2fs_proc_root = NULL; |
1573 | } |
1574 | |
1575 | int f2fs_register_sysfs(struct f2fs_sb_info *sbi) |
1576 | { |
1577 | struct super_block *sb = sbi->sb; |
1578 | int err; |
1579 | |
1580 | sbi->s_kobj.kset = &f2fs_kset; |
1581 | init_completion(x: &sbi->s_kobj_unregister); |
1582 | err = kobject_init_and_add(kobj: &sbi->s_kobj, ktype: &f2fs_sb_ktype, NULL, |
1583 | fmt: "%s" , sb->s_id); |
1584 | if (err) |
1585 | goto put_sb_kobj; |
1586 | |
1587 | sbi->s_stat_kobj.kset = &f2fs_kset; |
1588 | init_completion(x: &sbi->s_stat_kobj_unregister); |
1589 | err = kobject_init_and_add(kobj: &sbi->s_stat_kobj, ktype: &f2fs_stat_ktype, |
1590 | parent: &sbi->s_kobj, fmt: "stat" ); |
1591 | if (err) |
1592 | goto put_stat_kobj; |
1593 | |
1594 | sbi->s_feature_list_kobj.kset = &f2fs_kset; |
1595 | init_completion(x: &sbi->s_feature_list_kobj_unregister); |
1596 | err = kobject_init_and_add(kobj: &sbi->s_feature_list_kobj, |
1597 | ktype: &f2fs_feature_list_ktype, |
1598 | parent: &sbi->s_kobj, fmt: "feature_list" ); |
1599 | if (err) |
1600 | goto put_feature_list_kobj; |
1601 | |
1602 | sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); |
1603 | if (!sbi->s_proc) { |
1604 | err = -ENOMEM; |
1605 | goto put_feature_list_kobj; |
1606 | } |
1607 | |
1608 | proc_create_single_data(name: "segment_info" , mode: 0444, parent: sbi->s_proc, |
1609 | show: segment_info_seq_show, data: sb); |
1610 | proc_create_single_data(name: "segment_bits" , mode: 0444, parent: sbi->s_proc, |
1611 | show: segment_bits_seq_show, data: sb); |
1612 | #ifdef CONFIG_F2FS_IOSTAT |
1613 | proc_create_single_data(name: "iostat_info" , mode: 0444, parent: sbi->s_proc, |
1614 | show: iostat_info_seq_show, data: sb); |
1615 | #endif |
1616 | proc_create_single_data(name: "victim_bits" , mode: 0444, parent: sbi->s_proc, |
1617 | show: victim_bits_seq_show, data: sb); |
1618 | proc_create_single_data(name: "discard_plist_info" , mode: 0444, parent: sbi->s_proc, |
1619 | show: discard_plist_seq_show, data: sb); |
1620 | proc_create_single_data(name: "disk_map" , mode: 0444, parent: sbi->s_proc, |
1621 | show: disk_map_seq_show, data: sb); |
1622 | return 0; |
1623 | put_feature_list_kobj: |
1624 | kobject_put(kobj: &sbi->s_feature_list_kobj); |
1625 | wait_for_completion(&sbi->s_feature_list_kobj_unregister); |
1626 | put_stat_kobj: |
1627 | kobject_put(kobj: &sbi->s_stat_kobj); |
1628 | wait_for_completion(&sbi->s_stat_kobj_unregister); |
1629 | put_sb_kobj: |
1630 | kobject_put(kobj: &sbi->s_kobj); |
1631 | wait_for_completion(&sbi->s_kobj_unregister); |
1632 | return err; |
1633 | } |
1634 | |
1635 | void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) |
1636 | { |
1637 | remove_proc_subtree(sbi->sb->s_id, f2fs_proc_root); |
1638 | |
1639 | kobject_put(kobj: &sbi->s_stat_kobj); |
1640 | wait_for_completion(&sbi->s_stat_kobj_unregister); |
1641 | kobject_put(kobj: &sbi->s_feature_list_kobj); |
1642 | wait_for_completion(&sbi->s_feature_list_kobj_unregister); |
1643 | |
1644 | kobject_put(kobj: &sbi->s_kobj); |
1645 | wait_for_completion(&sbi->s_kobj_unregister); |
1646 | } |
1647 | |