| .. | .. |
|---|
| 11 | 11 | #include <linux/f2fs_fs.h> |
|---|
| 12 | 12 | #include <linux/seq_file.h> |
|---|
| 13 | 13 | #include <linux/unicode.h> |
|---|
| 14 | +#include <linux/ioprio.h> |
|---|
| 15 | +#include <linux/sysfs.h> |
|---|
| 14 | 16 | |
|---|
| 15 | 17 | #include "f2fs.h" |
|---|
| 16 | 18 | #include "segment.h" |
|---|
| .. | .. |
|---|
| 27 | 29 | NM_INFO, /* struct f2fs_nm_info */ |
|---|
| 28 | 30 | F2FS_SBI, /* struct f2fs_sb_info */ |
|---|
| 29 | 31 | #ifdef CONFIG_F2FS_STAT_FS |
|---|
| 30 | | - STAT_INFO, /* struct f2fs_stat_info */ |
|---|
| 32 | + STAT_INFO, /* struct f2fs_stat_info */ |
|---|
| 31 | 33 | #endif |
|---|
| 32 | 34 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
|---|
| 33 | 35 | FAULT_INFO_RATE, /* struct f2fs_fault_info */ |
|---|
| 34 | 36 | FAULT_INFO_TYPE, /* struct f2fs_fault_info */ |
|---|
| 35 | 37 | #endif |
|---|
| 36 | 38 | RESERVED_BLOCKS, /* struct f2fs_sb_info */ |
|---|
| 39 | + CPRC_INFO, /* struct ckpt_req_control */ |
|---|
| 40 | + ATGC_INFO, /* struct atgc_management */ |
|---|
| 37 | 41 | }; |
|---|
| 38 | 42 | |
|---|
| 39 | 43 | struct f2fs_attr { |
|---|
| .. | .. |
|---|
| 70 | 74 | else if (struct_type == STAT_INFO) |
|---|
| 71 | 75 | return (unsigned char *)F2FS_STAT(sbi); |
|---|
| 72 | 76 | #endif |
|---|
| 77 | + else if (struct_type == CPRC_INFO) |
|---|
| 78 | + return (unsigned char *)&sbi->cprc_info; |
|---|
| 79 | + else if (struct_type == ATGC_INFO) |
|---|
| 80 | + return (unsigned char *)&sbi->am; |
|---|
| 73 | 81 | return NULL; |
|---|
| 74 | 82 | } |
|---|
| 75 | 83 | |
|---|
| .. | .. |
|---|
| 87 | 95 | (unsigned long long)(free_segments(sbi))); |
|---|
| 88 | 96 | } |
|---|
| 89 | 97 | |
|---|
| 98 | +static ssize_t ovp_segments_show(struct f2fs_attr *a, |
|---|
| 99 | + struct f2fs_sb_info *sbi, char *buf) |
|---|
| 100 | +{ |
|---|
| 101 | + return sprintf(buf, "%llu\n", |
|---|
| 102 | + (unsigned long long)(overprovision_segments(sbi))); |
|---|
| 103 | +} |
|---|
| 104 | + |
|---|
| 90 | 105 | static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, |
|---|
| 91 | 106 | struct f2fs_sb_info *sbi, char *buf) |
|---|
| 92 | 107 | { |
|---|
| 93 | | - struct super_block *sb = sbi->sb; |
|---|
| 94 | | - |
|---|
| 95 | | - if (!sb->s_bdev->bd_part) |
|---|
| 96 | | - return sprintf(buf, "0\n"); |
|---|
| 97 | | - |
|---|
| 98 | 108 | return sprintf(buf, "%llu\n", |
|---|
| 99 | 109 | (unsigned long long)(sbi->kbytes_written + |
|---|
| 100 | | - BD_PART_WRITTEN(sbi))); |
|---|
| 110 | + ((f2fs_get_sectors_written(sbi) - |
|---|
| 111 | + sbi->sectors_written_start) >> 1))); |
|---|
| 112 | +} |
|---|
| 113 | + |
|---|
| 114 | +static ssize_t sb_status_show(struct f2fs_attr *a, |
|---|
| 115 | + struct f2fs_sb_info *sbi, char *buf) |
|---|
| 116 | +{ |
|---|
| 117 | + return sprintf(buf, "%lx\n", sbi->s_flag); |
|---|
| 118 | +} |
|---|
| 119 | + |
|---|
| 120 | +static ssize_t pending_discard_show(struct f2fs_attr *a, |
|---|
| 121 | + struct f2fs_sb_info *sbi, char *buf) |
|---|
| 122 | +{ |
|---|
| 123 | + if (!SM_I(sbi)->dcc_info) |
|---|
| 124 | + return -EINVAL; |
|---|
| 125 | + return sprintf(buf, "%llu\n", (unsigned long long)atomic_read( |
|---|
| 126 | + &SM_I(sbi)->dcc_info->discard_cmd_cnt)); |
|---|
| 101 | 127 | } |
|---|
| 102 | 128 | |
|---|
| 103 | 129 | static ssize_t features_show(struct f2fs_attr *a, |
|---|
| 104 | 130 | struct f2fs_sb_info *sbi, char *buf) |
|---|
| 105 | 131 | { |
|---|
| 106 | | - struct super_block *sb = sbi->sb; |
|---|
| 107 | 132 | int len = 0; |
|---|
| 108 | | - |
|---|
| 109 | | - if (!sb->s_bdev->bd_part) |
|---|
| 110 | | - return sprintf(buf, "0\n"); |
|---|
| 111 | 133 | |
|---|
| 112 | 134 | if (f2fs_sb_has_encrypt(sbi)) |
|---|
| 113 | 135 | len += scnprintf(buf, PAGE_SIZE - len, "%s", |
|---|
| .. | .. |
|---|
| 145 | 167 | if (f2fs_sb_has_casefold(sbi)) |
|---|
| 146 | 168 | len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", |
|---|
| 147 | 169 | len ? ", " : "", "casefold"); |
|---|
| 170 | + if (f2fs_sb_has_readonly(sbi)) |
|---|
| 171 | + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", |
|---|
| 172 | + len ? ", " : "", "readonly"); |
|---|
| 148 | 173 | if (f2fs_sb_has_compression(sbi)) |
|---|
| 149 | 174 | len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", |
|---|
| 150 | 175 | len ? ", " : "", "compression"); |
|---|
| .. | .. |
|---|
| 225 | 250 | } |
|---|
| 226 | 251 | #endif |
|---|
| 227 | 252 | |
|---|
| 253 | +static ssize_t main_blkaddr_show(struct f2fs_attr *a, |
|---|
| 254 | + struct f2fs_sb_info *sbi, char *buf) |
|---|
| 255 | +{ |
|---|
| 256 | + return snprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 257 | + (unsigned long long)MAIN_BLKADDR(sbi)); |
|---|
| 258 | +} |
|---|
| 259 | + |
|---|
| 228 | 260 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, |
|---|
| 229 | 261 | struct f2fs_sb_info *sbi, char *buf) |
|---|
| 230 | 262 | { |
|---|
| .. | .. |
|---|
| 254 | 286 | len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", |
|---|
| 255 | 287 | extlist[i]); |
|---|
| 256 | 288 | return len; |
|---|
| 289 | + } |
|---|
| 290 | + |
|---|
| 291 | + if (!strcmp(a->attr.name, "ckpt_thread_ioprio")) { |
|---|
| 292 | + struct ckpt_req_control *cprc = &sbi->cprc_info; |
|---|
| 293 | + int len = 0; |
|---|
| 294 | + int class = IOPRIO_PRIO_CLASS(cprc->ckpt_thread_ioprio); |
|---|
| 295 | + int data = IOPRIO_PRIO_DATA(cprc->ckpt_thread_ioprio); |
|---|
| 296 | + |
|---|
| 297 | + if (class == IOPRIO_CLASS_RT) |
|---|
| 298 | + len += scnprintf(buf + len, PAGE_SIZE - len, "rt,"); |
|---|
| 299 | + else if (class == IOPRIO_CLASS_BE) |
|---|
| 300 | + len += scnprintf(buf + len, PAGE_SIZE - len, "be,"); |
|---|
| 301 | + else |
|---|
| 302 | + return -EINVAL; |
|---|
| 303 | + |
|---|
| 304 | + len += scnprintf(buf + len, PAGE_SIZE - len, "%d\n", data); |
|---|
| 305 | + return len; |
|---|
| 306 | + } |
|---|
| 307 | + |
|---|
| 308 | +#ifdef CONFIG_F2FS_FS_COMPRESSION |
|---|
| 309 | + if (!strcmp(a->attr.name, "compr_written_block")) |
|---|
| 310 | + return sysfs_emit(buf, "%llu\n", sbi->compr_written_block); |
|---|
| 311 | + |
|---|
| 312 | + if (!strcmp(a->attr.name, "compr_saved_block")) |
|---|
| 313 | + return sysfs_emit(buf, "%llu\n", sbi->compr_saved_block); |
|---|
| 314 | + |
|---|
| 315 | + if (!strcmp(a->attr.name, "compr_new_inode")) |
|---|
| 316 | + return sysfs_emit(buf, "%u\n", sbi->compr_new_inode); |
|---|
| 317 | +#endif |
|---|
| 318 | + |
|---|
| 319 | + if (!strcmp(a->attr.name, "gc_segment_mode")) |
|---|
| 320 | + return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode); |
|---|
| 321 | + |
|---|
| 322 | + if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { |
|---|
| 323 | + return sysfs_emit(buf, "%u\n", |
|---|
| 324 | + sbi->gc_reclaimed_segs[sbi->gc_segment_mode]); |
|---|
| 257 | 325 | } |
|---|
| 258 | 326 | |
|---|
| 259 | 327 | ui = (unsigned int *)(ptr + a->offset); |
|---|
| .. | .. |
|---|
| 295 | 363 | if (strlen(name) >= F2FS_EXTENSION_LEN) |
|---|
| 296 | 364 | return -EINVAL; |
|---|
| 297 | 365 | |
|---|
| 298 | | - down_write(&sbi->sb_lock); |
|---|
| 366 | + f2fs_down_write(&sbi->sb_lock); |
|---|
| 299 | 367 | |
|---|
| 300 | 368 | ret = f2fs_update_extension_list(sbi, name, hot, set); |
|---|
| 301 | 369 | if (ret) |
|---|
| .. | .. |
|---|
| 305 | 373 | if (ret) |
|---|
| 306 | 374 | f2fs_update_extension_list(sbi, name, hot, !set); |
|---|
| 307 | 375 | out: |
|---|
| 308 | | - up_write(&sbi->sb_lock); |
|---|
| 376 | + f2fs_up_write(&sbi->sb_lock); |
|---|
| 309 | 377 | return ret ? ret : count; |
|---|
| 378 | + } |
|---|
| 379 | + |
|---|
| 380 | + if (!strcmp(a->attr.name, "ckpt_thread_ioprio")) { |
|---|
| 381 | + const char *name = strim((char *)buf); |
|---|
| 382 | + struct ckpt_req_control *cprc = &sbi->cprc_info; |
|---|
| 383 | + int class; |
|---|
| 384 | + long data; |
|---|
| 385 | + int ret; |
|---|
| 386 | + |
|---|
| 387 | + if (!strncmp(name, "rt,", 3)) |
|---|
| 388 | + class = IOPRIO_CLASS_RT; |
|---|
| 389 | + else if (!strncmp(name, "be,", 3)) |
|---|
| 390 | + class = IOPRIO_CLASS_BE; |
|---|
| 391 | + else |
|---|
| 392 | + return -EINVAL; |
|---|
| 393 | + |
|---|
| 394 | + name += 3; |
|---|
| 395 | + ret = kstrtol(name, 10, &data); |
|---|
| 396 | + if (ret) |
|---|
| 397 | + return ret; |
|---|
| 398 | + if (data >= IOPRIO_BE_NR || data < 0) |
|---|
| 399 | + return -EINVAL; |
|---|
| 400 | + |
|---|
| 401 | + cprc->ckpt_thread_ioprio = IOPRIO_PRIO_VALUE(class, data); |
|---|
| 402 | + if (test_opt(sbi, MERGE_CHECKPOINT)) { |
|---|
| 403 | + ret = set_task_ioprio(cprc->f2fs_issue_ckpt, |
|---|
| 404 | + cprc->ckpt_thread_ioprio); |
|---|
| 405 | + if (ret) |
|---|
| 406 | + return ret; |
|---|
| 407 | + } |
|---|
| 408 | + |
|---|
| 409 | + return count; |
|---|
| 310 | 410 | } |
|---|
| 311 | 411 | |
|---|
| 312 | 412 | ui = (unsigned int *)(ptr + a->offset); |
|---|
| .. | .. |
|---|
| 323 | 423 | if (a->struct_type == RESERVED_BLOCKS) { |
|---|
| 324 | 424 | spin_lock(&sbi->stat_lock); |
|---|
| 325 | 425 | if (t > (unsigned long)(sbi->user_block_count - |
|---|
| 326 | | - F2FS_OPTION(sbi).root_reserved_blocks)) { |
|---|
| 426 | + F2FS_OPTION(sbi).root_reserved_blocks - |
|---|
| 427 | + sbi->blocks_per_seg * |
|---|
| 428 | + SM_I(sbi)->additional_reserved_segments)) { |
|---|
| 327 | 429 | spin_unlock(&sbi->stat_lock); |
|---|
| 328 | 430 | return -EINVAL; |
|---|
| 329 | 431 | } |
|---|
| .. | .. |
|---|
| 352 | 454 | return -EINVAL; |
|---|
| 353 | 455 | |
|---|
| 354 | 456 | if (!strcmp(a->attr.name, "gc_urgent")) { |
|---|
| 355 | | - if (t >= 1) { |
|---|
| 356 | | - sbi->gc_mode = GC_URGENT; |
|---|
| 457 | + if (t == 0) { |
|---|
| 458 | + sbi->gc_mode = GC_NORMAL; |
|---|
| 459 | + } else if (t == 1) { |
|---|
| 460 | + sbi->gc_mode = GC_URGENT_HIGH; |
|---|
| 357 | 461 | if (sbi->gc_thread) { |
|---|
| 358 | 462 | sbi->gc_thread->gc_wake = 1; |
|---|
| 359 | 463 | wake_up_interruptible_all( |
|---|
| 360 | 464 | &sbi->gc_thread->gc_wait_queue_head); |
|---|
| 361 | 465 | wake_up_discard_thread(sbi, true); |
|---|
| 362 | 466 | } |
|---|
| 467 | + } else if (t == 2) { |
|---|
| 468 | + sbi->gc_mode = GC_URGENT_LOW; |
|---|
| 469 | + } else if (t == 3) { |
|---|
| 470 | + sbi->gc_mode = GC_URGENT_MID; |
|---|
| 471 | + if (sbi->gc_thread) { |
|---|
| 472 | + sbi->gc_thread->gc_wake = 1; |
|---|
| 473 | + wake_up_interruptible_all( |
|---|
| 474 | + &sbi->gc_thread->gc_wait_queue_head); |
|---|
| 475 | + } |
|---|
| 363 | 476 | } else { |
|---|
| 364 | | - sbi->gc_mode = GC_NORMAL; |
|---|
| 477 | + return -EINVAL; |
|---|
| 365 | 478 | } |
|---|
| 366 | 479 | return count; |
|---|
| 367 | 480 | } |
|---|
| 368 | 481 | if (!strcmp(a->attr.name, "gc_idle")) { |
|---|
| 369 | | - if (t == GC_IDLE_CB) |
|---|
| 482 | + if (t == GC_IDLE_CB) { |
|---|
| 370 | 483 | sbi->gc_mode = GC_IDLE_CB; |
|---|
| 371 | | - else if (t == GC_IDLE_GREEDY) |
|---|
| 484 | + } else if (t == GC_IDLE_GREEDY) { |
|---|
| 372 | 485 | sbi->gc_mode = GC_IDLE_GREEDY; |
|---|
| 373 | | - else |
|---|
| 486 | + } else if (t == GC_IDLE_AT) { |
|---|
| 487 | + if (!sbi->am.atgc_enabled) |
|---|
| 488 | + return -EINVAL; |
|---|
| 489 | + sbi->gc_mode = GC_IDLE_AT; |
|---|
| 490 | + } else { |
|---|
| 374 | 491 | sbi->gc_mode = GC_NORMAL; |
|---|
| 492 | + } |
|---|
| 375 | 493 | return count; |
|---|
| 376 | 494 | } |
|---|
| 377 | 495 | |
|---|
| .. | .. |
|---|
| 385 | 503 | if (!strcmp(a->attr.name, "iostat_period_ms")) { |
|---|
| 386 | 504 | if (t < MIN_IOSTAT_PERIOD_MS || t > MAX_IOSTAT_PERIOD_MS) |
|---|
| 387 | 505 | return -EINVAL; |
|---|
| 388 | | - spin_lock(&sbi->iostat_lock); |
|---|
| 506 | + spin_lock_irq(&sbi->iostat_lock); |
|---|
| 389 | 507 | sbi->iostat_period_ms = (unsigned int)t; |
|---|
| 390 | | - spin_unlock(&sbi->iostat_lock); |
|---|
| 508 | + spin_unlock_irq(&sbi->iostat_lock); |
|---|
| 509 | + return count; |
|---|
| 510 | + } |
|---|
| 511 | + |
|---|
| 512 | +#ifdef CONFIG_F2FS_FS_COMPRESSION |
|---|
| 513 | + if (!strcmp(a->attr.name, "compr_written_block") || |
|---|
| 514 | + !strcmp(a->attr.name, "compr_saved_block")) { |
|---|
| 515 | + if (t != 0) |
|---|
| 516 | + return -EINVAL; |
|---|
| 517 | + sbi->compr_written_block = 0; |
|---|
| 518 | + sbi->compr_saved_block = 0; |
|---|
| 519 | + return count; |
|---|
| 520 | + } |
|---|
| 521 | + |
|---|
| 522 | + if (!strcmp(a->attr.name, "compr_new_inode")) { |
|---|
| 523 | + if (t != 0) |
|---|
| 524 | + return -EINVAL; |
|---|
| 525 | + sbi->compr_new_inode = 0; |
|---|
| 526 | + return count; |
|---|
| 527 | + } |
|---|
| 528 | +#endif |
|---|
| 529 | + |
|---|
| 530 | + if (!strcmp(a->attr.name, "atgc_candidate_ratio")) { |
|---|
| 531 | + if (t > 100) |
|---|
| 532 | + return -EINVAL; |
|---|
| 533 | + sbi->am.candidate_ratio = t; |
|---|
| 534 | + return count; |
|---|
| 535 | + } |
|---|
| 536 | + |
|---|
| 537 | + if (!strcmp(a->attr.name, "atgc_age_weight")) { |
|---|
| 538 | + if (t > 100) |
|---|
| 539 | + return -EINVAL; |
|---|
| 540 | + sbi->am.age_weight = t; |
|---|
| 541 | + return count; |
|---|
| 542 | + } |
|---|
| 543 | + |
|---|
| 544 | + if (!strcmp(a->attr.name, "gc_segment_mode")) { |
|---|
| 545 | + if (t < MAX_GC_MODE) |
|---|
| 546 | + sbi->gc_segment_mode = t; |
|---|
| 547 | + else |
|---|
| 548 | + return -EINVAL; |
|---|
| 549 | + return count; |
|---|
| 550 | + } |
|---|
| 551 | + |
|---|
| 552 | + if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { |
|---|
| 553 | + if (t != 0) |
|---|
| 554 | + return -EINVAL; |
|---|
| 555 | + sbi->gc_reclaimed_segs[sbi->gc_segment_mode] = 0; |
|---|
| 556 | + return count; |
|---|
| 557 | + } |
|---|
| 558 | + |
|---|
| 559 | + if (!strcmp(a->attr.name, "hot_data_age_threshold")) { |
|---|
| 560 | + if (t == 0 || t >= sbi->warm_data_age_threshold) |
|---|
| 561 | + return -EINVAL; |
|---|
| 562 | + if (t == *ui) |
|---|
| 563 | + return count; |
|---|
| 564 | + *ui = (unsigned int)t; |
|---|
| 565 | + return count; |
|---|
| 566 | + } |
|---|
| 567 | + |
|---|
| 568 | + if (!strcmp(a->attr.name, "warm_data_age_threshold")) { |
|---|
| 569 | + if (t == 0 || t <= sbi->hot_data_age_threshold) |
|---|
| 570 | + return -EINVAL; |
|---|
| 571 | + if (t == *ui) |
|---|
| 572 | + return count; |
|---|
| 573 | + *ui = (unsigned int)t; |
|---|
| 574 | + return count; |
|---|
| 575 | + } |
|---|
| 576 | + |
|---|
| 577 | + if (!strcmp(a->attr.name, "last_age_weight")) { |
|---|
| 578 | + if (t > 100) |
|---|
| 579 | + return -EINVAL; |
|---|
| 580 | + if (t == *ui) |
|---|
| 581 | + return count; |
|---|
| 582 | + *ui = (unsigned int)t; |
|---|
| 391 | 583 | return count; |
|---|
| 392 | 584 | } |
|---|
| 393 | 585 | |
|---|
| .. | .. |
|---|
| 442 | 634 | complete(&sbi->s_kobj_unregister); |
|---|
| 443 | 635 | } |
|---|
| 444 | 636 | |
|---|
| 445 | | -enum feat_id { |
|---|
| 446 | | - FEAT_CRYPTO = 0, |
|---|
| 447 | | - FEAT_BLKZONED, |
|---|
| 448 | | - FEAT_ATOMIC_WRITE, |
|---|
| 449 | | - FEAT_EXTRA_ATTR, |
|---|
| 450 | | - FEAT_PROJECT_QUOTA, |
|---|
| 451 | | - FEAT_INODE_CHECKSUM, |
|---|
| 452 | | - FEAT_FLEXIBLE_INLINE_XATTR, |
|---|
| 453 | | - FEAT_QUOTA_INO, |
|---|
| 454 | | - FEAT_INODE_CRTIME, |
|---|
| 455 | | - FEAT_LOST_FOUND, |
|---|
| 456 | | - FEAT_VERITY, |
|---|
| 457 | | - FEAT_SB_CHECKSUM, |
|---|
| 458 | | - FEAT_CASEFOLD, |
|---|
| 459 | | - FEAT_COMPRESSION, |
|---|
| 460 | | - FEAT_TEST_DUMMY_ENCRYPTION_V2, |
|---|
| 461 | | -}; |
|---|
| 462 | | - |
|---|
| 637 | +/* |
|---|
| 638 | + * Note that there are three feature list entries: |
|---|
| 639 | + * 1) /sys/fs/f2fs/features |
|---|
| 640 | + * : shows runtime features supported by in-kernel f2fs along with Kconfig. |
|---|
| 641 | + * - ref. F2FS_FEATURE_RO_ATTR() |
|---|
| 642 | + * |
|---|
| 643 | + * 2) /sys/fs/f2fs/$s_id/features <deprecated> |
|---|
| 644 | + * : shows on-disk features enabled by mkfs.f2fs, used for old kernels. This |
|---|
| 645 | + * won't add new feature anymore, and thus, users should check entries in 3) |
|---|
| 646 | + * instead of this 2). |
|---|
| 647 | + * |
|---|
| 648 | + * 3) /sys/fs/f2fs/$s_id/feature_list |
|---|
| 649 | + * : shows on-disk features enabled by mkfs.f2fs per instance, which follows |
|---|
| 650 | + * sysfs entry rule where each entry should expose single value. |
|---|
| 651 | + * This list covers old feature list provided by 2) and beyond. Therefore, |
|---|
| 652 | + * please add new on-disk feature in this list only. |
|---|
| 653 | + * - ref. F2FS_SB_FEATURE_RO_ATTR() |
|---|
| 654 | + */ |
|---|
| 463 | 655 | static ssize_t f2fs_feature_show(struct f2fs_attr *a, |
|---|
| 464 | 656 | struct f2fs_sb_info *sbi, char *buf) |
|---|
| 465 | 657 | { |
|---|
| 466 | | - switch (a->id) { |
|---|
| 467 | | - case FEAT_CRYPTO: |
|---|
| 468 | | - case FEAT_BLKZONED: |
|---|
| 469 | | - case FEAT_ATOMIC_WRITE: |
|---|
| 470 | | - case FEAT_EXTRA_ATTR: |
|---|
| 471 | | - case FEAT_PROJECT_QUOTA: |
|---|
| 472 | | - case FEAT_INODE_CHECKSUM: |
|---|
| 473 | | - case FEAT_FLEXIBLE_INLINE_XATTR: |
|---|
| 474 | | - case FEAT_QUOTA_INO: |
|---|
| 475 | | - case FEAT_INODE_CRTIME: |
|---|
| 476 | | - case FEAT_LOST_FOUND: |
|---|
| 477 | | - case FEAT_VERITY: |
|---|
| 478 | | - case FEAT_SB_CHECKSUM: |
|---|
| 479 | | - case FEAT_CASEFOLD: |
|---|
| 480 | | - case FEAT_COMPRESSION: |
|---|
| 481 | | - case FEAT_TEST_DUMMY_ENCRYPTION_V2: |
|---|
| 658 | + return sprintf(buf, "supported\n"); |
|---|
| 659 | +} |
|---|
| 660 | + |
|---|
| 661 | +#define F2FS_FEATURE_RO_ATTR(_name) \ |
|---|
| 662 | +static struct f2fs_attr f2fs_attr_##_name = { \ |
|---|
| 663 | + .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
|---|
| 664 | + .show = f2fs_feature_show, \ |
|---|
| 665 | +} |
|---|
| 666 | + |
|---|
| 667 | +static ssize_t f2fs_sb_feature_show(struct f2fs_attr *a, |
|---|
| 668 | + struct f2fs_sb_info *sbi, char *buf) |
|---|
| 669 | +{ |
|---|
| 670 | + if (F2FS_HAS_FEATURE(sbi, a->id)) |
|---|
| 482 | 671 | return sprintf(buf, "supported\n"); |
|---|
| 483 | | - } |
|---|
| 484 | | - return 0; |
|---|
| 672 | + return sprintf(buf, "unsupported\n"); |
|---|
| 673 | +} |
|---|
| 674 | + |
|---|
| 675 | +#define F2FS_SB_FEATURE_RO_ATTR(_name, _feat) \ |
|---|
| 676 | +static struct f2fs_attr f2fs_attr_sb_##_name = { \ |
|---|
| 677 | + .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
|---|
| 678 | + .show = f2fs_sb_feature_show, \ |
|---|
| 679 | + .id = F2FS_FEATURE_##_feat, \ |
|---|
| 485 | 680 | } |
|---|
| 486 | 681 | |
|---|
| 487 | 682 | #define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ |
|---|
| .. | .. |
|---|
| 501 | 696 | #define F2FS_GENERAL_RO_ATTR(name) \ |
|---|
| 502 | 697 | static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) |
|---|
| 503 | 698 | |
|---|
| 504 | | -#define F2FS_FEATURE_RO_ATTR(_name, _id) \ |
|---|
| 505 | | -static struct f2fs_attr f2fs_attr_##_name = { \ |
|---|
| 506 | | - .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
|---|
| 507 | | - .show = f2fs_feature_show, \ |
|---|
| 508 | | - .id = _id, \ |
|---|
| 509 | | -} |
|---|
| 510 | | - |
|---|
| 511 | 699 | #define F2FS_STAT_ATTR(_struct_type, _struct_name, _name, _elname) \ |
|---|
| 512 | 700 | static struct f2fs_attr f2fs_attr_##_name = { \ |
|---|
| 513 | 701 | .attr = {.name = __stringify(_name), .mode = 0444 }, \ |
|---|
| .. | .. |
|---|
| 524 | 712 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode); |
|---|
| 525 | 713 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode); |
|---|
| 526 | 714 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); |
|---|
| 527 | | -F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, main_blkaddr, main_blkaddr); |
|---|
| 528 | 715 | F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); |
|---|
| 529 | 716 | F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); |
|---|
| 530 | 717 | F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks); |
|---|
| .. | .. |
|---|
| 551 | 738 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); |
|---|
| 552 | 739 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_period_ms, iostat_period_ms); |
|---|
| 553 | 740 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); |
|---|
| 741 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_io_bytes, max_io_bytes); |
|---|
| 554 | 742 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); |
|---|
| 555 | 743 | F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); |
|---|
| 556 | 744 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
|---|
| .. | .. |
|---|
| 559 | 747 | #endif |
|---|
| 560 | 748 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag); |
|---|
| 561 | 749 | F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag); |
|---|
| 750 | +F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio); |
|---|
| 562 | 751 | F2FS_GENERAL_RO_ATTR(dirty_segments); |
|---|
| 563 | 752 | F2FS_GENERAL_RO_ATTR(free_segments); |
|---|
| 753 | +F2FS_GENERAL_RO_ATTR(ovp_segments); |
|---|
| 564 | 754 | F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); |
|---|
| 565 | 755 | F2FS_GENERAL_RO_ATTR(features); |
|---|
| 566 | 756 | F2FS_GENERAL_RO_ATTR(current_reserved_blocks); |
|---|
| 567 | 757 | F2FS_GENERAL_RO_ATTR(unusable); |
|---|
| 568 | 758 | F2FS_GENERAL_RO_ATTR(encoding); |
|---|
| 569 | 759 | F2FS_GENERAL_RO_ATTR(mounted_time_sec); |
|---|
| 760 | +F2FS_GENERAL_RO_ATTR(main_blkaddr); |
|---|
| 761 | +F2FS_GENERAL_RO_ATTR(pending_discard); |
|---|
| 570 | 762 | #ifdef CONFIG_F2FS_STAT_FS |
|---|
| 571 | 763 | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count); |
|---|
| 572 | 764 | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count); |
|---|
| .. | .. |
|---|
| 578 | 770 | #endif |
|---|
| 579 | 771 | |
|---|
| 580 | 772 | #ifdef CONFIG_FS_ENCRYPTION |
|---|
| 581 | | -F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); |
|---|
| 582 | | -F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2, FEAT_TEST_DUMMY_ENCRYPTION_V2); |
|---|
| 773 | +F2FS_FEATURE_RO_ATTR(encryption); |
|---|
| 774 | +F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2); |
|---|
| 775 | +#ifdef CONFIG_UNICODE |
|---|
| 776 | +F2FS_FEATURE_RO_ATTR(encrypted_casefold); |
|---|
| 583 | 777 | #endif |
|---|
| 778 | +#endif /* CONFIG_FS_ENCRYPTION */ |
|---|
| 584 | 779 | #ifdef CONFIG_BLK_DEV_ZONED |
|---|
| 585 | | -F2FS_FEATURE_RO_ATTR(block_zoned, FEAT_BLKZONED); |
|---|
| 780 | +F2FS_FEATURE_RO_ATTR(block_zoned); |
|---|
| 586 | 781 | #endif |
|---|
| 587 | | -F2FS_FEATURE_RO_ATTR(atomic_write, FEAT_ATOMIC_WRITE); |
|---|
| 588 | | -F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR); |
|---|
| 589 | | -F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA); |
|---|
| 590 | | -F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM); |
|---|
| 591 | | -F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); |
|---|
| 592 | | -F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); |
|---|
| 593 | | -F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); |
|---|
| 594 | | -F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); |
|---|
| 782 | +F2FS_FEATURE_RO_ATTR(atomic_write); |
|---|
| 783 | +F2FS_FEATURE_RO_ATTR(extra_attr); |
|---|
| 784 | +F2FS_FEATURE_RO_ATTR(project_quota); |
|---|
| 785 | +F2FS_FEATURE_RO_ATTR(inode_checksum); |
|---|
| 786 | +F2FS_FEATURE_RO_ATTR(flexible_inline_xattr); |
|---|
| 787 | +F2FS_FEATURE_RO_ATTR(quota_ino); |
|---|
| 788 | +F2FS_FEATURE_RO_ATTR(inode_crtime); |
|---|
| 789 | +F2FS_FEATURE_RO_ATTR(lost_found); |
|---|
| 595 | 790 | #ifdef CONFIG_FS_VERITY |
|---|
| 596 | | -F2FS_FEATURE_RO_ATTR(verity, FEAT_VERITY); |
|---|
| 791 | +F2FS_FEATURE_RO_ATTR(verity); |
|---|
| 597 | 792 | #endif |
|---|
| 598 | | -F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); |
|---|
| 599 | | -F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD); |
|---|
| 793 | +F2FS_FEATURE_RO_ATTR(sb_checksum); |
|---|
| 794 | +#ifdef CONFIG_UNICODE |
|---|
| 795 | +F2FS_FEATURE_RO_ATTR(casefold); |
|---|
| 796 | +#endif |
|---|
| 797 | +F2FS_FEATURE_RO_ATTR(readonly); |
|---|
| 600 | 798 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
|---|
| 601 | | -F2FS_FEATURE_RO_ATTR(compression, FEAT_COMPRESSION); |
|---|
| 799 | +F2FS_FEATURE_RO_ATTR(compression); |
|---|
| 800 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_written_block, compr_written_block); |
|---|
| 801 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_saved_block, compr_saved_block); |
|---|
| 802 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_new_inode, compr_new_inode); |
|---|
| 602 | 803 | #endif |
|---|
| 804 | +F2FS_FEATURE_RO_ATTR(pin_file); |
|---|
| 805 | + |
|---|
| 806 | +/* For ATGC */ |
|---|
| 807 | +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_ratio, candidate_ratio); |
|---|
| 808 | +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_count, max_candidate_count); |
|---|
| 809 | +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_weight, age_weight); |
|---|
| 810 | +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold); |
|---|
| 811 | + |
|---|
| 812 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_segment_mode, gc_segment_mode); |
|---|
| 813 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_reclaimed_segments, gc_reclaimed_segs); |
|---|
| 814 | + |
|---|
| 815 | +/* For block age extent cache */ |
|---|
| 816 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, hot_data_age_threshold, hot_data_age_threshold); |
|---|
| 817 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, warm_data_age_threshold, warm_data_age_threshold); |
|---|
| 818 | +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, last_age_weight, last_age_weight); |
|---|
| 603 | 819 | |
|---|
| 604 | 820 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) |
|---|
| 605 | 821 | static struct attribute *f2fs_attrs[] = { |
|---|
| .. | .. |
|---|
| 613 | 829 | ATTR_LIST(main_blkaddr), |
|---|
| 614 | 830 | ATTR_LIST(max_small_discards), |
|---|
| 615 | 831 | ATTR_LIST(discard_granularity), |
|---|
| 832 | + ATTR_LIST(pending_discard), |
|---|
| 616 | 833 | ATTR_LIST(batched_trim_sections), |
|---|
| 617 | 834 | ATTR_LIST(ipu_policy), |
|---|
| 618 | 835 | ATTR_LIST(min_ipu_util), |
|---|
| .. | .. |
|---|
| 634 | 851 | ATTR_LIST(iostat_enable), |
|---|
| 635 | 852 | ATTR_LIST(iostat_period_ms), |
|---|
| 636 | 853 | ATTR_LIST(readdir_ra), |
|---|
| 854 | + ATTR_LIST(max_io_bytes), |
|---|
| 637 | 855 | ATTR_LIST(gc_pin_file_thresh), |
|---|
| 638 | 856 | ATTR_LIST(extension_list), |
|---|
| 639 | 857 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
|---|
| .. | .. |
|---|
| 642 | 860 | #endif |
|---|
| 643 | 861 | ATTR_LIST(data_io_flag), |
|---|
| 644 | 862 | ATTR_LIST(node_io_flag), |
|---|
| 863 | + ATTR_LIST(ckpt_thread_ioprio), |
|---|
| 645 | 864 | ATTR_LIST(dirty_segments), |
|---|
| 646 | 865 | ATTR_LIST(free_segments), |
|---|
| 866 | + ATTR_LIST(ovp_segments), |
|---|
| 647 | 867 | ATTR_LIST(unusable), |
|---|
| 648 | 868 | ATTR_LIST(lifetime_write_kbytes), |
|---|
| 649 | 869 | ATTR_LIST(features), |
|---|
| .. | .. |
|---|
| 660 | 880 | ATTR_LIST(moved_blocks_background), |
|---|
| 661 | 881 | ATTR_LIST(avg_vblocks), |
|---|
| 662 | 882 | #endif |
|---|
| 883 | +#ifdef CONFIG_F2FS_FS_COMPRESSION |
|---|
| 884 | + ATTR_LIST(compr_written_block), |
|---|
| 885 | + ATTR_LIST(compr_saved_block), |
|---|
| 886 | + ATTR_LIST(compr_new_inode), |
|---|
| 887 | +#endif |
|---|
| 888 | + /* For ATGC */ |
|---|
| 889 | + ATTR_LIST(atgc_candidate_ratio), |
|---|
| 890 | + ATTR_LIST(atgc_candidate_count), |
|---|
| 891 | + ATTR_LIST(atgc_age_weight), |
|---|
| 892 | + ATTR_LIST(atgc_age_threshold), |
|---|
| 893 | + ATTR_LIST(gc_segment_mode), |
|---|
| 894 | + ATTR_LIST(gc_reclaimed_segments), |
|---|
| 895 | + ATTR_LIST(hot_data_age_threshold), |
|---|
| 896 | + ATTR_LIST(warm_data_age_threshold), |
|---|
| 897 | + ATTR_LIST(last_age_weight), |
|---|
| 663 | 898 | NULL, |
|---|
| 664 | 899 | }; |
|---|
| 900 | +ATTRIBUTE_GROUPS(f2fs); |
|---|
| 665 | 901 | |
|---|
| 666 | 902 | static struct attribute *f2fs_feat_attrs[] = { |
|---|
| 667 | 903 | #ifdef CONFIG_FS_ENCRYPTION |
|---|
| 668 | 904 | ATTR_LIST(encryption), |
|---|
| 669 | 905 | ATTR_LIST(test_dummy_encryption_v2), |
|---|
| 906 | +#ifdef CONFIG_UNICODE |
|---|
| 907 | + ATTR_LIST(encrypted_casefold), |
|---|
| 670 | 908 | #endif |
|---|
| 909 | +#endif /* CONFIG_FS_ENCRYPTION */ |
|---|
| 671 | 910 | #ifdef CONFIG_BLK_DEV_ZONED |
|---|
| 672 | 911 | ATTR_LIST(block_zoned), |
|---|
| 673 | 912 | #endif |
|---|
| .. | .. |
|---|
| 683 | 922 | ATTR_LIST(verity), |
|---|
| 684 | 923 | #endif |
|---|
| 685 | 924 | ATTR_LIST(sb_checksum), |
|---|
| 925 | +#ifdef CONFIG_UNICODE |
|---|
| 686 | 926 | ATTR_LIST(casefold), |
|---|
| 927 | +#endif |
|---|
| 928 | + ATTR_LIST(readonly), |
|---|
| 687 | 929 | #ifdef CONFIG_F2FS_FS_COMPRESSION |
|---|
| 688 | 930 | ATTR_LIST(compression), |
|---|
| 689 | 931 | #endif |
|---|
| 932 | + ATTR_LIST(pin_file), |
|---|
| 690 | 933 | NULL, |
|---|
| 691 | 934 | }; |
|---|
| 935 | +ATTRIBUTE_GROUPS(f2fs_feat); |
|---|
| 936 | + |
|---|
| 937 | +F2FS_GENERAL_RO_ATTR(sb_status); |
|---|
| 938 | +static struct attribute *f2fs_stat_attrs[] = { |
|---|
| 939 | + ATTR_LIST(sb_status), |
|---|
| 940 | + NULL, |
|---|
| 941 | +}; |
|---|
| 942 | +ATTRIBUTE_GROUPS(f2fs_stat); |
|---|
| 943 | + |
|---|
| 944 | +F2FS_SB_FEATURE_RO_ATTR(encryption, ENCRYPT); |
|---|
| 945 | +F2FS_SB_FEATURE_RO_ATTR(block_zoned, BLKZONED); |
|---|
| 946 | +F2FS_SB_FEATURE_RO_ATTR(extra_attr, EXTRA_ATTR); |
|---|
| 947 | +F2FS_SB_FEATURE_RO_ATTR(project_quota, PRJQUOTA); |
|---|
| 948 | +F2FS_SB_FEATURE_RO_ATTR(inode_checksum, INODE_CHKSUM); |
|---|
| 949 | +F2FS_SB_FEATURE_RO_ATTR(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); |
|---|
| 950 | +F2FS_SB_FEATURE_RO_ATTR(quota_ino, QUOTA_INO); |
|---|
| 951 | +F2FS_SB_FEATURE_RO_ATTR(inode_crtime, INODE_CRTIME); |
|---|
| 952 | +F2FS_SB_FEATURE_RO_ATTR(lost_found, LOST_FOUND); |
|---|
| 953 | +F2FS_SB_FEATURE_RO_ATTR(verity, VERITY); |
|---|
| 954 | +F2FS_SB_FEATURE_RO_ATTR(sb_checksum, SB_CHKSUM); |
|---|
| 955 | +F2FS_SB_FEATURE_RO_ATTR(casefold, CASEFOLD); |
|---|
| 956 | +F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION); |
|---|
| 957 | +F2FS_SB_FEATURE_RO_ATTR(readonly, RO); |
|---|
| 958 | + |
|---|
| 959 | +static struct attribute *f2fs_sb_feat_attrs[] = { |
|---|
| 960 | + ATTR_LIST(sb_encryption), |
|---|
| 961 | + ATTR_LIST(sb_block_zoned), |
|---|
| 962 | + ATTR_LIST(sb_extra_attr), |
|---|
| 963 | + ATTR_LIST(sb_project_quota), |
|---|
| 964 | + ATTR_LIST(sb_inode_checksum), |
|---|
| 965 | + ATTR_LIST(sb_flexible_inline_xattr), |
|---|
| 966 | + ATTR_LIST(sb_quota_ino), |
|---|
| 967 | + ATTR_LIST(sb_inode_crtime), |
|---|
| 968 | + ATTR_LIST(sb_lost_found), |
|---|
| 969 | + ATTR_LIST(sb_verity), |
|---|
| 970 | + ATTR_LIST(sb_sb_checksum), |
|---|
| 971 | + ATTR_LIST(sb_casefold), |
|---|
| 972 | + ATTR_LIST(sb_compression), |
|---|
| 973 | + ATTR_LIST(sb_readonly), |
|---|
| 974 | + NULL, |
|---|
| 975 | +}; |
|---|
| 976 | +ATTRIBUTE_GROUPS(f2fs_sb_feat); |
|---|
| 692 | 977 | |
|---|
| 693 | 978 | static const struct sysfs_ops f2fs_attr_ops = { |
|---|
| 694 | 979 | .show = f2fs_attr_show, |
|---|
| .. | .. |
|---|
| 696 | 981 | }; |
|---|
| 697 | 982 | |
|---|
| 698 | 983 | static struct kobj_type f2fs_sb_ktype = { |
|---|
| 699 | | - .default_attrs = f2fs_attrs, |
|---|
| 984 | + .default_groups = f2fs_groups, |
|---|
| 700 | 985 | .sysfs_ops = &f2fs_attr_ops, |
|---|
| 701 | 986 | .release = f2fs_sb_release, |
|---|
| 702 | 987 | }; |
|---|
| .. | .. |
|---|
| 706 | 991 | }; |
|---|
| 707 | 992 | |
|---|
| 708 | 993 | static struct kset f2fs_kset = { |
|---|
| 709 | | - .kobj = {.ktype = &f2fs_ktype}, |
|---|
| 994 | + .kobj = {.ktype = &f2fs_ktype}, |
|---|
| 710 | 995 | }; |
|---|
| 711 | 996 | |
|---|
| 712 | 997 | static struct kobj_type f2fs_feat_ktype = { |
|---|
| 713 | | - .default_attrs = f2fs_feat_attrs, |
|---|
| 998 | + .default_groups = f2fs_feat_groups, |
|---|
| 714 | 999 | .sysfs_ops = &f2fs_attr_ops, |
|---|
| 715 | 1000 | }; |
|---|
| 716 | 1001 | |
|---|
| 717 | 1002 | static struct kobject f2fs_feat = { |
|---|
| 718 | 1003 | .kset = &f2fs_kset, |
|---|
| 1004 | +}; |
|---|
| 1005 | + |
|---|
| 1006 | +static ssize_t f2fs_stat_attr_show(struct kobject *kobj, |
|---|
| 1007 | + struct attribute *attr, char *buf) |
|---|
| 1008 | +{ |
|---|
| 1009 | + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
|---|
| 1010 | + s_stat_kobj); |
|---|
| 1011 | + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
|---|
| 1012 | + |
|---|
| 1013 | + return a->show ? a->show(a, sbi, buf) : 0; |
|---|
| 1014 | +} |
|---|
| 1015 | + |
|---|
| 1016 | +static ssize_t f2fs_stat_attr_store(struct kobject *kobj, struct attribute *attr, |
|---|
| 1017 | + const char *buf, size_t len) |
|---|
| 1018 | +{ |
|---|
| 1019 | + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
|---|
| 1020 | + s_stat_kobj); |
|---|
| 1021 | + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
|---|
| 1022 | + |
|---|
| 1023 | + return a->store ? a->store(a, sbi, buf, len) : 0; |
|---|
| 1024 | +} |
|---|
| 1025 | + |
|---|
| 1026 | +static void f2fs_stat_kobj_release(struct kobject *kobj) |
|---|
| 1027 | +{ |
|---|
| 1028 | + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
|---|
| 1029 | + s_stat_kobj); |
|---|
| 1030 | + complete(&sbi->s_stat_kobj_unregister); |
|---|
| 1031 | +} |
|---|
| 1032 | + |
|---|
| 1033 | +static const struct sysfs_ops f2fs_stat_attr_ops = { |
|---|
| 1034 | + .show = f2fs_stat_attr_show, |
|---|
| 1035 | + .store = f2fs_stat_attr_store, |
|---|
| 1036 | +}; |
|---|
| 1037 | + |
|---|
| 1038 | +static struct kobj_type f2fs_stat_ktype = { |
|---|
| 1039 | + .default_groups = f2fs_stat_groups, |
|---|
| 1040 | + .sysfs_ops = &f2fs_stat_attr_ops, |
|---|
| 1041 | + .release = f2fs_stat_kobj_release, |
|---|
| 1042 | +}; |
|---|
| 1043 | + |
|---|
| 1044 | +static ssize_t f2fs_sb_feat_attr_show(struct kobject *kobj, |
|---|
| 1045 | + struct attribute *attr, char *buf) |
|---|
| 1046 | +{ |
|---|
| 1047 | + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
|---|
| 1048 | + s_feature_list_kobj); |
|---|
| 1049 | + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); |
|---|
| 1050 | + |
|---|
| 1051 | + return a->show ? a->show(a, sbi, buf) : 0; |
|---|
| 1052 | +} |
|---|
| 1053 | + |
|---|
| 1054 | +static void f2fs_feature_list_kobj_release(struct kobject *kobj) |
|---|
| 1055 | +{ |
|---|
| 1056 | + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, |
|---|
| 1057 | + s_feature_list_kobj); |
|---|
| 1058 | + complete(&sbi->s_feature_list_kobj_unregister); |
|---|
| 1059 | +} |
|---|
| 1060 | + |
|---|
| 1061 | +static const struct sysfs_ops f2fs_feature_list_attr_ops = { |
|---|
| 1062 | + .show = f2fs_sb_feat_attr_show, |
|---|
| 1063 | +}; |
|---|
| 1064 | + |
|---|
| 1065 | +static struct kobj_type f2fs_feature_list_ktype = { |
|---|
| 1066 | + .default_groups = f2fs_sb_feat_groups, |
|---|
| 1067 | + .sysfs_ops = &f2fs_feature_list_attr_ops, |
|---|
| 1068 | + .release = f2fs_feature_list_kobj_release, |
|---|
| 719 | 1069 | }; |
|---|
| 720 | 1070 | |
|---|
| 721 | 1071 | static int __maybe_unused segment_info_seq_show(struct seq_file *seq, |
|---|
| .. | .. |
|---|
| 924 | 1274 | init_completion(&sbi->s_kobj_unregister); |
|---|
| 925 | 1275 | err = kobject_init_and_add(&sbi->s_kobj, &f2fs_sb_ktype, NULL, |
|---|
| 926 | 1276 | "%s", sb->s_id); |
|---|
| 927 | | - if (err) { |
|---|
| 928 | | - kobject_put(&sbi->s_kobj); |
|---|
| 929 | | - wait_for_completion(&sbi->s_kobj_unregister); |
|---|
| 930 | | - return err; |
|---|
| 931 | | - } |
|---|
| 1277 | + if (err) |
|---|
| 1278 | + goto put_sb_kobj; |
|---|
| 1279 | + |
|---|
| 1280 | + sbi->s_stat_kobj.kset = &f2fs_kset; |
|---|
| 1281 | + init_completion(&sbi->s_stat_kobj_unregister); |
|---|
| 1282 | + err = kobject_init_and_add(&sbi->s_stat_kobj, &f2fs_stat_ktype, |
|---|
| 1283 | + &sbi->s_kobj, "stat"); |
|---|
| 1284 | + if (err) |
|---|
| 1285 | + goto put_stat_kobj; |
|---|
| 1286 | + |
|---|
| 1287 | + sbi->s_feature_list_kobj.kset = &f2fs_kset; |
|---|
| 1288 | + init_completion(&sbi->s_feature_list_kobj_unregister); |
|---|
| 1289 | + err = kobject_init_and_add(&sbi->s_feature_list_kobj, |
|---|
| 1290 | + &f2fs_feature_list_ktype, |
|---|
| 1291 | + &sbi->s_kobj, "feature_list"); |
|---|
| 1292 | + if (err) |
|---|
| 1293 | + goto put_feature_list_kobj; |
|---|
| 932 | 1294 | |
|---|
| 933 | 1295 | if (f2fs_proc_root) |
|---|
| 934 | 1296 | sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); |
|---|
| .. | .. |
|---|
| 944 | 1306 | victim_bits_seq_show, sb); |
|---|
| 945 | 1307 | } |
|---|
| 946 | 1308 | return 0; |
|---|
| 1309 | +put_feature_list_kobj: |
|---|
| 1310 | + kobject_put(&sbi->s_feature_list_kobj); |
|---|
| 1311 | + wait_for_completion(&sbi->s_feature_list_kobj_unregister); |
|---|
| 1312 | +put_stat_kobj: |
|---|
| 1313 | + kobject_put(&sbi->s_stat_kobj); |
|---|
| 1314 | + wait_for_completion(&sbi->s_stat_kobj_unregister); |
|---|
| 1315 | +put_sb_kobj: |
|---|
| 1316 | + kobject_put(&sbi->s_kobj); |
|---|
| 1317 | + wait_for_completion(&sbi->s_kobj_unregister); |
|---|
| 1318 | + return err; |
|---|
| 947 | 1319 | } |
|---|
| 948 | 1320 | |
|---|
| 949 | 1321 | void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) |
|---|
| .. | .. |
|---|
| 955 | 1327 | remove_proc_entry("victim_bits", sbi->s_proc); |
|---|
| 956 | 1328 | remove_proc_entry(sbi->sb->s_id, f2fs_proc_root); |
|---|
| 957 | 1329 | } |
|---|
| 1330 | + |
|---|
| 1331 | + kobject_del(&sbi->s_stat_kobj); |
|---|
| 1332 | + kobject_put(&sbi->s_stat_kobj); |
|---|
| 1333 | + wait_for_completion(&sbi->s_stat_kobj_unregister); |
|---|
| 1334 | + kobject_del(&sbi->s_feature_list_kobj); |
|---|
| 1335 | + kobject_put(&sbi->s_feature_list_kobj); |
|---|
| 1336 | + wait_for_completion(&sbi->s_feature_list_kobj_unregister); |
|---|
| 1337 | + |
|---|
| 958 | 1338 | kobject_del(&sbi->s_kobj); |
|---|
| 959 | 1339 | kobject_put(&sbi->s_kobj); |
|---|
| 960 | 1340 | wait_for_completion(&sbi->s_kobj_unregister); |
|---|