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