diff options
author | Theodore Ts'o <tytso@mit.edu> | 2015-09-23 12:44:17 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-09-23 12:44:17 -0400 |
commit | b5799018827e67867fda77c3cde10fc080606fe2 (patch) | |
tree | ebd4cc981162d55bef49b45ff86c846923411ef8 | |
parent | 1f93e4a96c9109378204c147b3eec0d0e8100fde (diff) |
ext4: move sysfs code from super.c to fs/ext4/sysfs.c
Also statically allocate the ext4_kset and ext4_feat objects, since we
only need exactly one of each, and it's simpler and less code if we
drop the dynamic allocation and deallocation when it's not needed.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | fs/ext4/Makefile | 2 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 5 | ||||
-rw-r--r-- | fs/ext4/super.c | 426 | ||||
-rw-r--r-- | fs/ext4/sysfs.c | 387 |
4 files changed, 410 insertions, 410 deletions
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 75285ea9aa05..f52cf54f0cbc 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile | |||
@@ -8,7 +8,7 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ | |||
8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ | 8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ |
9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ | 9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ |
10 | mmp.o indirect.o extents_status.o xattr.o xattr_user.o \ | 10 | mmp.o indirect.o extents_status.o xattr.o xattr_user.o \ |
11 | xattr_trusted.o inline.o readpage.o | 11 | xattr_trusted.o inline.o readpage.o sysfs.o |
12 | 12 | ||
13 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o | 13 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o |
14 | ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o | 14 | ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index fd1f28be5296..76daccf38aa3 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2903,6 +2903,11 @@ extern const struct inode_operations ext4_encrypted_symlink_inode_operations; | |||
2903 | extern const struct inode_operations ext4_symlink_inode_operations; | 2903 | extern const struct inode_operations ext4_symlink_inode_operations; |
2904 | extern const struct inode_operations ext4_fast_symlink_inode_operations; | 2904 | extern const struct inode_operations ext4_fast_symlink_inode_operations; |
2905 | 2905 | ||
2906 | /* sysfs.c */ | ||
2907 | extern int ext4_register_sysfs(struct super_block *sb); | ||
2908 | extern int __init ext4_init_sysfs(void); | ||
2909 | extern void ext4_exit_sysfs(void); | ||
2910 | |||
2906 | /* block_validity */ | 2911 | /* block_validity */ |
2907 | extern void ext4_release_system_zone(struct super_block *sb); | 2912 | extern void ext4_release_system_zone(struct super_block *sb); |
2908 | extern int ext4_setup_system_zone(struct super_block *sb); | 2913 | extern int ext4_setup_system_zone(struct super_block *sb); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index a63c7b0a10cf..4a574fbeffec 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -55,10 +55,8 @@ | |||
55 | #include <trace/events/ext4.h> | 55 | #include <trace/events/ext4.h> |
56 | 56 | ||
57 | static struct proc_dir_entry *ext4_proc_root; | 57 | static struct proc_dir_entry *ext4_proc_root; |
58 | static struct kset *ext4_kset; | ||
59 | static struct ext4_lazy_init *ext4_li_info; | 58 | static struct ext4_lazy_init *ext4_li_info; |
60 | static struct mutex ext4_li_mtx; | 59 | static struct mutex ext4_li_mtx; |
61 | static struct ext4_features *ext4_feat; | ||
62 | static int ext4_mballoc_ready; | 60 | static int ext4_mballoc_ready; |
63 | static struct ratelimit_state ext4_mount_msg_ratelimit; | 61 | static struct ratelimit_state ext4_mount_msg_ratelimit; |
64 | 62 | ||
@@ -83,7 +81,6 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly); | |||
83 | static void ext4_destroy_lazyinit_thread(void); | 81 | static void ext4_destroy_lazyinit_thread(void); |
84 | static void ext4_unregister_li_request(struct super_block *sb); | 82 | static void ext4_unregister_li_request(struct super_block *sb); |
85 | static void ext4_clear_request_list(void); | 83 | static void ext4_clear_request_list(void); |
86 | static int ext4_reserve_clusters(struct ext4_sb_info *, ext4_fsblk_t); | ||
87 | 84 | ||
88 | #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) | 85 | #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) |
89 | static struct file_system_type ext2_fs_type = { | 86 | static struct file_system_type ext2_fs_type = { |
@@ -2470,335 +2467,6 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) | |||
2470 | return ret; | 2467 | return ret; |
2471 | } | 2468 | } |
2472 | 2469 | ||
2473 | /* sysfs supprt */ | ||
2474 | |||
2475 | struct ext4_attr { | ||
2476 | struct attribute attr; | ||
2477 | ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *); | ||
2478 | ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, | ||
2479 | const char *, size_t); | ||
2480 | union { | ||
2481 | int offset; | ||
2482 | int deprecated_val; | ||
2483 | } u; | ||
2484 | }; | ||
2485 | |||
2486 | static int parse_strtoull(const char *buf, | ||
2487 | unsigned long long max, unsigned long long *value) | ||
2488 | { | ||
2489 | int ret; | ||
2490 | |||
2491 | ret = kstrtoull(skip_spaces(buf), 0, value); | ||
2492 | if (!ret && *value > max) | ||
2493 | ret = -EINVAL; | ||
2494 | return ret; | ||
2495 | } | ||
2496 | |||
2497 | static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a, | ||
2498 | struct ext4_sb_info *sbi, | ||
2499 | char *buf) | ||
2500 | { | ||
2501 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
2502 | (s64) EXT4_C2B(sbi, | ||
2503 | percpu_counter_sum(&sbi->s_dirtyclusters_counter))); | ||
2504 | } | ||
2505 | |||
2506 | static ssize_t session_write_kbytes_show(struct ext4_attr *a, | ||
2507 | struct ext4_sb_info *sbi, char *buf) | ||
2508 | { | ||
2509 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
2510 | |||
2511 | if (!sb->s_bdev->bd_part) | ||
2512 | return snprintf(buf, PAGE_SIZE, "0\n"); | ||
2513 | return snprintf(buf, PAGE_SIZE, "%lu\n", | ||
2514 | (part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
2515 | sbi->s_sectors_written_start) >> 1); | ||
2516 | } | ||
2517 | |||
2518 | static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a, | ||
2519 | struct ext4_sb_info *sbi, char *buf) | ||
2520 | { | ||
2521 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
2522 | |||
2523 | if (!sb->s_bdev->bd_part) | ||
2524 | return snprintf(buf, PAGE_SIZE, "0\n"); | ||
2525 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
2526 | (unsigned long long)(sbi->s_kbytes_written + | ||
2527 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
2528 | EXT4_SB(sb)->s_sectors_written_start) >> 1))); | ||
2529 | } | ||
2530 | |||
2531 | static ssize_t inode_readahead_blks_store(struct ext4_attr *a, | ||
2532 | struct ext4_sb_info *sbi, | ||
2533 | const char *buf, size_t count) | ||
2534 | { | ||
2535 | unsigned long t; | ||
2536 | int ret; | ||
2537 | |||
2538 | ret = kstrtoul(skip_spaces(buf), 0, &t); | ||
2539 | if (ret) | ||
2540 | return ret; | ||
2541 | |||
2542 | if (t && (!is_power_of_2(t) || t > 0x40000000)) | ||
2543 | return -EINVAL; | ||
2544 | |||
2545 | sbi->s_inode_readahead_blks = t; | ||
2546 | return count; | ||
2547 | } | ||
2548 | |||
2549 | static ssize_t sbi_ui_show(struct ext4_attr *a, | ||
2550 | struct ext4_sb_info *sbi, char *buf) | ||
2551 | { | ||
2552 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); | ||
2553 | |||
2554 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | ||
2555 | } | ||
2556 | |||
2557 | static ssize_t sbi_ui_store(struct ext4_attr *a, | ||
2558 | struct ext4_sb_info *sbi, | ||
2559 | const char *buf, size_t count) | ||
2560 | { | ||
2561 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); | ||
2562 | unsigned long t; | ||
2563 | int ret; | ||
2564 | |||
2565 | ret = kstrtoul(skip_spaces(buf), 0, &t); | ||
2566 | if (ret) | ||
2567 | return ret; | ||
2568 | *ui = t; | ||
2569 | return count; | ||
2570 | } | ||
2571 | |||
2572 | static ssize_t es_ui_show(struct ext4_attr *a, | ||
2573 | struct ext4_sb_info *sbi, char *buf) | ||
2574 | { | ||
2575 | |||
2576 | unsigned int *ui = (unsigned int *) (((char *) sbi->s_es) + | ||
2577 | a->u.offset); | ||
2578 | |||
2579 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | ||
2580 | } | ||
2581 | |||
2582 | static ssize_t reserved_clusters_show(struct ext4_attr *a, | ||
2583 | struct ext4_sb_info *sbi, char *buf) | ||
2584 | { | ||
2585 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
2586 | (unsigned long long) atomic64_read(&sbi->s_resv_clusters)); | ||
2587 | } | ||
2588 | |||
2589 | static ssize_t reserved_clusters_store(struct ext4_attr *a, | ||
2590 | struct ext4_sb_info *sbi, | ||
2591 | const char *buf, size_t count) | ||
2592 | { | ||
2593 | unsigned long long val; | ||
2594 | int ret; | ||
2595 | |||
2596 | if (parse_strtoull(buf, -1ULL, &val)) | ||
2597 | return -EINVAL; | ||
2598 | ret = ext4_reserve_clusters(sbi, val); | ||
2599 | |||
2600 | return ret ? ret : count; | ||
2601 | } | ||
2602 | |||
2603 | static ssize_t trigger_test_error(struct ext4_attr *a, | ||
2604 | struct ext4_sb_info *sbi, | ||
2605 | const char *buf, size_t count) | ||
2606 | { | ||
2607 | int len = count; | ||
2608 | |||
2609 | if (!capable(CAP_SYS_ADMIN)) | ||
2610 | return -EPERM; | ||
2611 | |||
2612 | if (len && buf[len-1] == '\n') | ||
2613 | len--; | ||
2614 | |||
2615 | if (len) | ||
2616 | ext4_error(sbi->s_sb, "%.*s", len, buf); | ||
2617 | return count; | ||
2618 | } | ||
2619 | |||
2620 | static ssize_t sbi_deprecated_show(struct ext4_attr *a, | ||
2621 | struct ext4_sb_info *sbi, char *buf) | ||
2622 | { | ||
2623 | return snprintf(buf, PAGE_SIZE, "%d\n", a->u.deprecated_val); | ||
2624 | } | ||
2625 | |||
2626 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ | ||
2627 | static struct ext4_attr ext4_attr_##_name = { \ | ||
2628 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
2629 | .show = _show, \ | ||
2630 | .store = _store, \ | ||
2631 | .u = { \ | ||
2632 | .offset = offsetof(struct ext4_sb_info, _elname),\ | ||
2633 | }, \ | ||
2634 | } | ||
2635 | |||
2636 | #define EXT4_ATTR_OFFSET_ES(_name,_mode,_show,_store,_elname) \ | ||
2637 | static struct ext4_attr ext4_attr_##_name = { \ | ||
2638 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
2639 | .show = _show, \ | ||
2640 | .store = _store, \ | ||
2641 | .u = { \ | ||
2642 | .offset = offsetof(struct ext4_super_block, _elname), \ | ||
2643 | }, \ | ||
2644 | } | ||
2645 | |||
2646 | #define EXT4_ATTR(name, mode, show, store) \ | ||
2647 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) | ||
2648 | |||
2649 | #define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL) | ||
2650 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) | ||
2651 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) | ||
2652 | |||
2653 | #define EXT4_RO_ATTR_ES_UI(name, elname) \ | ||
2654 | EXT4_ATTR_OFFSET_ES(name, 0444, es_ui_show, NULL, elname) | ||
2655 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ | ||
2656 | EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname) | ||
2657 | |||
2658 | #define ATTR_LIST(name) &ext4_attr_##name.attr | ||
2659 | #define EXT4_DEPRECATED_ATTR(_name, _val) \ | ||
2660 | static struct ext4_attr ext4_attr_##_name = { \ | ||
2661 | .attr = {.name = __stringify(_name), .mode = 0444 }, \ | ||
2662 | .show = sbi_deprecated_show, \ | ||
2663 | .u = { \ | ||
2664 | .deprecated_val = _val, \ | ||
2665 | }, \ | ||
2666 | } | ||
2667 | |||
2668 | EXT4_RO_ATTR(delayed_allocation_blocks); | ||
2669 | EXT4_RO_ATTR(session_write_kbytes); | ||
2670 | EXT4_RO_ATTR(lifetime_write_kbytes); | ||
2671 | EXT4_RW_ATTR(reserved_clusters); | ||
2672 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, | ||
2673 | inode_readahead_blks_store, s_inode_readahead_blks); | ||
2674 | EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); | ||
2675 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); | ||
2676 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); | ||
2677 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); | ||
2678 | EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); | ||
2679 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); | ||
2680 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); | ||
2681 | EXT4_DEPRECATED_ATTR(max_writeback_mb_bump, 128); | ||
2682 | EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); | ||
2683 | EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); | ||
2684 | EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval); | ||
2685 | EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst); | ||
2686 | EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval); | ||
2687 | EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst); | ||
2688 | EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval); | ||
2689 | EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst); | ||
2690 | EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); | ||
2691 | EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time); | ||
2692 | EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time); | ||
2693 | |||
2694 | static struct attribute *ext4_attrs[] = { | ||
2695 | ATTR_LIST(delayed_allocation_blocks), | ||
2696 | ATTR_LIST(session_write_kbytes), | ||
2697 | ATTR_LIST(lifetime_write_kbytes), | ||
2698 | ATTR_LIST(reserved_clusters), | ||
2699 | ATTR_LIST(inode_readahead_blks), | ||
2700 | ATTR_LIST(inode_goal), | ||
2701 | ATTR_LIST(mb_stats), | ||
2702 | ATTR_LIST(mb_max_to_scan), | ||
2703 | ATTR_LIST(mb_min_to_scan), | ||
2704 | ATTR_LIST(mb_order2_req), | ||
2705 | ATTR_LIST(mb_stream_req), | ||
2706 | ATTR_LIST(mb_group_prealloc), | ||
2707 | ATTR_LIST(max_writeback_mb_bump), | ||
2708 | ATTR_LIST(extent_max_zeroout_kb), | ||
2709 | ATTR_LIST(trigger_fs_error), | ||
2710 | ATTR_LIST(err_ratelimit_interval_ms), | ||
2711 | ATTR_LIST(err_ratelimit_burst), | ||
2712 | ATTR_LIST(warning_ratelimit_interval_ms), | ||
2713 | ATTR_LIST(warning_ratelimit_burst), | ||
2714 | ATTR_LIST(msg_ratelimit_interval_ms), | ||
2715 | ATTR_LIST(msg_ratelimit_burst), | ||
2716 | ATTR_LIST(errors_count), | ||
2717 | ATTR_LIST(first_error_time), | ||
2718 | ATTR_LIST(last_error_time), | ||
2719 | NULL, | ||
2720 | }; | ||
2721 | |||
2722 | /* Features this copy of ext4 supports */ | ||
2723 | EXT4_INFO_ATTR(lazy_itable_init); | ||
2724 | EXT4_INFO_ATTR(batched_discard); | ||
2725 | EXT4_INFO_ATTR(meta_bg_resize); | ||
2726 | EXT4_INFO_ATTR(encryption); | ||
2727 | |||
2728 | static struct attribute *ext4_feat_attrs[] = { | ||
2729 | ATTR_LIST(lazy_itable_init), | ||
2730 | ATTR_LIST(batched_discard), | ||
2731 | ATTR_LIST(meta_bg_resize), | ||
2732 | ATTR_LIST(encryption), | ||
2733 | NULL, | ||
2734 | }; | ||
2735 | |||
2736 | static ssize_t ext4_attr_show(struct kobject *kobj, | ||
2737 | struct attribute *attr, char *buf) | ||
2738 | { | ||
2739 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2740 | s_kobj); | ||
2741 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
2742 | |||
2743 | return a->show ? a->show(a, sbi, buf) : 0; | ||
2744 | } | ||
2745 | |||
2746 | static ssize_t ext4_attr_store(struct kobject *kobj, | ||
2747 | struct attribute *attr, | ||
2748 | const char *buf, size_t len) | ||
2749 | { | ||
2750 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2751 | s_kobj); | ||
2752 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
2753 | |||
2754 | return a->store ? a->store(a, sbi, buf, len) : 0; | ||
2755 | } | ||
2756 | |||
2757 | static void ext4_sb_release(struct kobject *kobj) | ||
2758 | { | ||
2759 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2760 | s_kobj); | ||
2761 | complete(&sbi->s_kobj_unregister); | ||
2762 | } | ||
2763 | |||
2764 | static const struct sysfs_ops ext4_attr_ops = { | ||
2765 | .show = ext4_attr_show, | ||
2766 | .store = ext4_attr_store, | ||
2767 | }; | ||
2768 | |||
2769 | static struct kobj_type ext4_ktype = { | ||
2770 | .default_attrs = ext4_attrs, | ||
2771 | .sysfs_ops = &ext4_attr_ops, | ||
2772 | .release = ext4_sb_release, | ||
2773 | }; | ||
2774 | |||
2775 | static void ext4_feat_release(struct kobject *kobj) | ||
2776 | { | ||
2777 | complete(&ext4_feat->f_kobj_unregister); | ||
2778 | } | ||
2779 | |||
2780 | static ssize_t ext4_feat_show(struct kobject *kobj, | ||
2781 | struct attribute *attr, char *buf) | ||
2782 | { | ||
2783 | return snprintf(buf, PAGE_SIZE, "supported\n"); | ||
2784 | } | ||
2785 | |||
2786 | /* | ||
2787 | * We can not use ext4_attr_show/store because it relies on the kobject | ||
2788 | * being embedded in the ext4_sb_info structure which is definitely not | ||
2789 | * true in this case. | ||
2790 | */ | ||
2791 | static const struct sysfs_ops ext4_feat_ops = { | ||
2792 | .show = ext4_feat_show, | ||
2793 | .store = NULL, | ||
2794 | }; | ||
2795 | |||
2796 | static struct kobj_type ext4_feat_ktype = { | ||
2797 | .default_attrs = ext4_feat_attrs, | ||
2798 | .sysfs_ops = &ext4_feat_ops, | ||
2799 | .release = ext4_feat_release, | ||
2800 | }; | ||
2801 | |||
2802 | /* | 2470 | /* |
2803 | * Check whether this filesystem can be mounted based on | 2471 | * Check whether this filesystem can be mounted based on |
2804 | * the features present and the RDONLY/RDWR mount requested. | 2472 | * the features present and the RDONLY/RDWR mount requested. |
@@ -3403,10 +3071,10 @@ int ext4_calculate_overhead(struct super_block *sb) | |||
3403 | return 0; | 3071 | return 0; |
3404 | } | 3072 | } |
3405 | 3073 | ||
3406 | 3074 | static void ext4_set_resv_clusters(struct super_block *sb) | |
3407 | static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb) | ||
3408 | { | 3075 | { |
3409 | ext4_fsblk_t resv_clusters; | 3076 | ext4_fsblk_t resv_clusters; |
3077 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
3410 | 3078 | ||
3411 | /* | 3079 | /* |
3412 | * There's no need to reserve anything when we aren't using extents. | 3080 | * There's no need to reserve anything when we aren't using extents. |
@@ -3415,7 +3083,7 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb) | |||
3415 | * to keep ext2/3 backward compatibility. | 3083 | * to keep ext2/3 backward compatibility. |
3416 | */ | 3084 | */ |
3417 | if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) | 3085 | if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) |
3418 | return 0; | 3086 | return; |
3419 | /* | 3087 | /* |
3420 | * By default we reserve 2% or 4096 clusters, whichever is smaller. | 3088 | * By default we reserve 2% or 4096 clusters, whichever is smaller. |
3421 | * This should cover the situations where we can not afford to run | 3089 | * This should cover the situations where we can not afford to run |
@@ -3424,26 +3092,13 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb) | |||
3424 | * allocation would require 1, or 2 blocks, higher numbers are | 3092 | * allocation would require 1, or 2 blocks, higher numbers are |
3425 | * very rare. | 3093 | * very rare. |
3426 | */ | 3094 | */ |
3427 | resv_clusters = ext4_blocks_count(EXT4_SB(sb)->s_es) >> | 3095 | resv_clusters = (ext4_blocks_count(sbi->s_es) >> |
3428 | EXT4_SB(sb)->s_cluster_bits; | 3096 | sbi->s_cluster_bits); |
3429 | 3097 | ||
3430 | do_div(resv_clusters, 50); | 3098 | do_div(resv_clusters, 50); |
3431 | resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096); | 3099 | resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096); |
3432 | 3100 | ||
3433 | return resv_clusters; | 3101 | atomic64_set(&sbi->s_resv_clusters, resv_clusters); |
3434 | } | ||
3435 | |||
3436 | |||
3437 | static int ext4_reserve_clusters(struct ext4_sb_info *sbi, ext4_fsblk_t count) | ||
3438 | { | ||
3439 | ext4_fsblk_t clusters = ext4_blocks_count(sbi->s_es) >> | ||
3440 | sbi->s_cluster_bits; | ||
3441 | |||
3442 | if (count >= clusters) | ||
3443 | return -EINVAL; | ||
3444 | |||
3445 | atomic64_set(&sbi->s_resv_clusters, count); | ||
3446 | return 0; | ||
3447 | } | 3102 | } |
3448 | 3103 | ||
3449 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 3104 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
@@ -4192,12 +3847,7 @@ no_journal: | |||
4192 | "available"); | 3847 | "available"); |
4193 | } | 3848 | } |
4194 | 3849 | ||
4195 | err = ext4_reserve_clusters(sbi, ext4_calculate_resv_clusters(sb)); | 3850 | ext4_set_resv_clusters(sb); |
4196 | if (err) { | ||
4197 | ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for " | ||
4198 | "reserved pool", ext4_calculate_resv_clusters(sb)); | ||
4199 | goto failed_mount4a; | ||
4200 | } | ||
4201 | 3851 | ||
4202 | err = ext4_setup_system_zone(sb); | 3852 | err = ext4_setup_system_zone(sb); |
4203 | if (err) { | 3853 | if (err) { |
@@ -4248,10 +3898,7 @@ no_journal: | |||
4248 | if (err) | 3898 | if (err) |
4249 | goto failed_mount6; | 3899 | goto failed_mount6; |
4250 | 3900 | ||
4251 | sbi->s_kobj.kset = ext4_kset; | 3901 | err = ext4_register_sysfs(sb); |
4252 | init_completion(&sbi->s_kobj_unregister); | ||
4253 | err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL, | ||
4254 | "%s", sb->s_id); | ||
4255 | if (err) | 3902 | if (err) |
4256 | goto failed_mount7; | 3903 | goto failed_mount7; |
4257 | 3904 | ||
@@ -5586,37 +5233,6 @@ static struct file_system_type ext4_fs_type = { | |||
5586 | }; | 5233 | }; |
5587 | MODULE_ALIAS_FS("ext4"); | 5234 | MODULE_ALIAS_FS("ext4"); |
5588 | 5235 | ||
5589 | static int __init ext4_init_feat_adverts(void) | ||
5590 | { | ||
5591 | struct ext4_features *ef; | ||
5592 | int ret = -ENOMEM; | ||
5593 | |||
5594 | ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL); | ||
5595 | if (!ef) | ||
5596 | goto out; | ||
5597 | |||
5598 | ef->f_kobj.kset = ext4_kset; | ||
5599 | init_completion(&ef->f_kobj_unregister); | ||
5600 | ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL, | ||
5601 | "features"); | ||
5602 | if (ret) { | ||
5603 | kfree(ef); | ||
5604 | goto out; | ||
5605 | } | ||
5606 | |||
5607 | ext4_feat = ef; | ||
5608 | ret = 0; | ||
5609 | out: | ||
5610 | return ret; | ||
5611 | } | ||
5612 | |||
5613 | static void ext4_exit_feat_adverts(void) | ||
5614 | { | ||
5615 | kobject_put(&ext4_feat->f_kobj); | ||
5616 | wait_for_completion(&ext4_feat->f_kobj_unregister); | ||
5617 | kfree(ext4_feat); | ||
5618 | } | ||
5619 | |||
5620 | /* Shared across all ext4 file systems */ | 5236 | /* Shared across all ext4 file systems */ |
5621 | wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; | 5237 | wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; |
5622 | struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; | 5238 | struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; |
@@ -5643,21 +5259,16 @@ static int __init ext4_init_fs(void) | |||
5643 | 5259 | ||
5644 | err = ext4_init_pageio(); | 5260 | err = ext4_init_pageio(); |
5645 | if (err) | 5261 | if (err) |
5646 | goto out7; | 5262 | goto out5; |
5647 | 5263 | ||
5648 | err = ext4_init_system_zone(); | 5264 | err = ext4_init_system_zone(); |
5649 | if (err) | 5265 | if (err) |
5650 | goto out6; | 5266 | goto out4; |
5651 | ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj); | ||
5652 | if (!ext4_kset) { | ||
5653 | err = -ENOMEM; | ||
5654 | goto out5; | ||
5655 | } | ||
5656 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); | 5267 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); |
5657 | 5268 | ||
5658 | err = ext4_init_feat_adverts(); | 5269 | err = ext4_init_sysfs(); |
5659 | if (err) | 5270 | if (err) |
5660 | goto out4; | 5271 | goto out3; |
5661 | 5272 | ||
5662 | err = ext4_init_mballoc(); | 5273 | err = ext4_init_mballoc(); |
5663 | if (err) | 5274 | if (err) |
@@ -5682,16 +5293,14 @@ out1: | |||
5682 | ext4_mballoc_ready = 0; | 5293 | ext4_mballoc_ready = 0; |
5683 | ext4_exit_mballoc(); | 5294 | ext4_exit_mballoc(); |
5684 | out2: | 5295 | out2: |
5685 | ext4_exit_feat_adverts(); | 5296 | ext4_exit_sysfs(); |
5686 | out4: | 5297 | out3: |
5687 | if (ext4_proc_root) | 5298 | if (ext4_proc_root) |
5688 | remove_proc_entry("fs/ext4", NULL); | 5299 | remove_proc_entry("fs/ext4", NULL); |
5689 | kset_unregister(ext4_kset); | ||
5690 | out5: | ||
5691 | ext4_exit_system_zone(); | 5300 | ext4_exit_system_zone(); |
5692 | out6: | 5301 | out4: |
5693 | ext4_exit_pageio(); | 5302 | ext4_exit_pageio(); |
5694 | out7: | 5303 | out5: |
5695 | ext4_exit_es(); | 5304 | ext4_exit_es(); |
5696 | 5305 | ||
5697 | return err; | 5306 | return err; |
@@ -5706,9 +5315,8 @@ static void __exit ext4_exit_fs(void) | |||
5706 | unregister_filesystem(&ext4_fs_type); | 5315 | unregister_filesystem(&ext4_fs_type); |
5707 | destroy_inodecache(); | 5316 | destroy_inodecache(); |
5708 | ext4_exit_mballoc(); | 5317 | ext4_exit_mballoc(); |
5709 | ext4_exit_feat_adverts(); | 5318 | ext4_exit_sysfs(); |
5710 | remove_proc_entry("fs/ext4", NULL); | 5319 | remove_proc_entry("fs/ext4", NULL); |
5711 | kset_unregister(ext4_kset); | ||
5712 | ext4_exit_system_zone(); | 5320 | ext4_exit_system_zone(); |
5713 | ext4_exit_pageio(); | 5321 | ext4_exit_pageio(); |
5714 | ext4_exit_es(); | 5322 | ext4_exit_es(); |
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c new file mode 100644 index 000000000000..9fdc21b9b265 --- /dev/null +++ b/fs/ext4/sysfs.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * linux/fs/ext4/sysfs.c | ||
3 | * | ||
4 | * Copyright (C) 1992, 1993, 1994, 1995 | ||
5 | * Remy Card (card@masi.ibp.fr) | ||
6 | * Theodore Ts'o (tytso@mit.edu) | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/time.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/seq_file.h> | ||
13 | #include <linux/proc_fs.h> | ||
14 | |||
15 | #include "ext4.h" | ||
16 | #include "ext4_jbd2.h" | ||
17 | |||
18 | struct ext4_attr { | ||
19 | struct attribute attr; | ||
20 | ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *); | ||
21 | ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, | ||
22 | const char *, size_t); | ||
23 | union { | ||
24 | int offset; | ||
25 | int deprecated_val; | ||
26 | } u; | ||
27 | }; | ||
28 | |||
29 | static int parse_strtoull(const char *buf, | ||
30 | unsigned long long max, unsigned long long *value) | ||
31 | { | ||
32 | int ret; | ||
33 | |||
34 | ret = kstrtoull(skip_spaces(buf), 0, value); | ||
35 | if (!ret && *value > max) | ||
36 | ret = -EINVAL; | ||
37 | return ret; | ||
38 | } | ||
39 | |||
40 | static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a, | ||
41 | struct ext4_sb_info *sbi, | ||
42 | char *buf) | ||
43 | { | ||
44 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
45 | (s64) EXT4_C2B(sbi, | ||
46 | percpu_counter_sum(&sbi->s_dirtyclusters_counter))); | ||
47 | } | ||
48 | |||
49 | static ssize_t session_write_kbytes_show(struct ext4_attr *a, | ||
50 | struct ext4_sb_info *sbi, char *buf) | ||
51 | { | ||
52 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
53 | |||
54 | if (!sb->s_bdev->bd_part) | ||
55 | return snprintf(buf, PAGE_SIZE, "0\n"); | ||
56 | return snprintf(buf, PAGE_SIZE, "%lu\n", | ||
57 | (part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
58 | sbi->s_sectors_written_start) >> 1); | ||
59 | } | ||
60 | |||
61 | static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a, | ||
62 | struct ext4_sb_info *sbi, char *buf) | ||
63 | { | ||
64 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
65 | |||
66 | if (!sb->s_bdev->bd_part) | ||
67 | return snprintf(buf, PAGE_SIZE, "0\n"); | ||
68 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
69 | (unsigned long long)(sbi->s_kbytes_written + | ||
70 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
71 | EXT4_SB(sb)->s_sectors_written_start) >> 1))); | ||
72 | } | ||
73 | |||
74 | static ssize_t inode_readahead_blks_store(struct ext4_attr *a, | ||
75 | struct ext4_sb_info *sbi, | ||
76 | const char *buf, size_t count) | ||
77 | { | ||
78 | unsigned long t; | ||
79 | int ret; | ||
80 | |||
81 | ret = kstrtoul(skip_spaces(buf), 0, &t); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | if (t && (!is_power_of_2(t) || t > 0x40000000)) | ||
86 | return -EINVAL; | ||
87 | |||
88 | sbi->s_inode_readahead_blks = t; | ||
89 | return count; | ||
90 | } | ||
91 | |||
92 | static ssize_t sbi_ui_show(struct ext4_attr *a, | ||
93 | struct ext4_sb_info *sbi, char *buf) | ||
94 | { | ||
95 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); | ||
96 | |||
97 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | ||
98 | } | ||
99 | |||
100 | static ssize_t sbi_ui_store(struct ext4_attr *a, | ||
101 | struct ext4_sb_info *sbi, | ||
102 | const char *buf, size_t count) | ||
103 | { | ||
104 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); | ||
105 | unsigned long t; | ||
106 | int ret; | ||
107 | |||
108 | ret = kstrtoul(skip_spaces(buf), 0, &t); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | *ui = t; | ||
112 | return count; | ||
113 | } | ||
114 | |||
115 | static ssize_t es_ui_show(struct ext4_attr *a, | ||
116 | struct ext4_sb_info *sbi, char *buf) | ||
117 | { | ||
118 | |||
119 | unsigned int *ui = (unsigned int *) (((char *) sbi->s_es) + | ||
120 | a->u.offset); | ||
121 | |||
122 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | ||
123 | } | ||
124 | |||
125 | static ssize_t reserved_clusters_show(struct ext4_attr *a, | ||
126 | struct ext4_sb_info *sbi, char *buf) | ||
127 | { | ||
128 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
129 | (unsigned long long) atomic64_read(&sbi->s_resv_clusters)); | ||
130 | } | ||
131 | |||
132 | static ssize_t reserved_clusters_store(struct ext4_attr *a, | ||
133 | struct ext4_sb_info *sbi, | ||
134 | const char *buf, size_t count) | ||
135 | { | ||
136 | unsigned long long val; | ||
137 | ext4_fsblk_t clusters = (ext4_blocks_count(sbi->s_es) >> | ||
138 | sbi->s_cluster_bits); | ||
139 | |||
140 | if (parse_strtoull(buf, -1ULL, &val)) | ||
141 | return -EINVAL; | ||
142 | |||
143 | if (val >= clusters) | ||
144 | return -EINVAL; | ||
145 | |||
146 | atomic64_set(&sbi->s_resv_clusters, val); | ||
147 | return count; | ||
148 | } | ||
149 | |||
150 | static ssize_t trigger_test_error(struct ext4_attr *a, | ||
151 | struct ext4_sb_info *sbi, | ||
152 | const char *buf, size_t count) | ||
153 | { | ||
154 | int len = count; | ||
155 | |||
156 | if (!capable(CAP_SYS_ADMIN)) | ||
157 | return -EPERM; | ||
158 | |||
159 | if (len && buf[len-1] == '\n') | ||
160 | len--; | ||
161 | |||
162 | if (len) | ||
163 | ext4_error(sbi->s_sb, "%.*s", len, buf); | ||
164 | return count; | ||
165 | } | ||
166 | |||
167 | static ssize_t sbi_deprecated_show(struct ext4_attr *a, | ||
168 | struct ext4_sb_info *sbi, char *buf) | ||
169 | { | ||
170 | return snprintf(buf, PAGE_SIZE, "%d\n", a->u.deprecated_val); | ||
171 | } | ||
172 | |||
173 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ | ||
174 | static struct ext4_attr ext4_attr_##_name = { \ | ||
175 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
176 | .show = _show, \ | ||
177 | .store = _store, \ | ||
178 | .u = { \ | ||
179 | .offset = offsetof(struct ext4_sb_info, _elname),\ | ||
180 | }, \ | ||
181 | } | ||
182 | |||
183 | #define EXT4_ATTR_OFFSET_ES(_name,_mode,_show,_store,_elname) \ | ||
184 | static struct ext4_attr ext4_attr_##_name = { \ | ||
185 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
186 | .show = _show, \ | ||
187 | .store = _store, \ | ||
188 | .u = { \ | ||
189 | .offset = offsetof(struct ext4_super_block, _elname), \ | ||
190 | }, \ | ||
191 | } | ||
192 | |||
193 | #define EXT4_ATTR(name, mode, show, store) \ | ||
194 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) | ||
195 | |||
196 | #define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL) | ||
197 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) | ||
198 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) | ||
199 | |||
200 | #define EXT4_RO_ATTR_ES_UI(name, elname) \ | ||
201 | EXT4_ATTR_OFFSET_ES(name, 0444, es_ui_show, NULL, elname) | ||
202 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ | ||
203 | EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname) | ||
204 | |||
205 | #define ATTR_LIST(name) &ext4_attr_##name.attr | ||
206 | #define EXT4_DEPRECATED_ATTR(_name, _val) \ | ||
207 | static struct ext4_attr ext4_attr_##_name = { \ | ||
208 | .attr = {.name = __stringify(_name), .mode = 0444 }, \ | ||
209 | .show = sbi_deprecated_show, \ | ||
210 | .u = { \ | ||
211 | .deprecated_val = _val, \ | ||
212 | }, \ | ||
213 | } | ||
214 | |||
215 | EXT4_RO_ATTR(delayed_allocation_blocks); | ||
216 | EXT4_RO_ATTR(session_write_kbytes); | ||
217 | EXT4_RO_ATTR(lifetime_write_kbytes); | ||
218 | EXT4_RW_ATTR(reserved_clusters); | ||
219 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, | ||
220 | inode_readahead_blks_store, s_inode_readahead_blks); | ||
221 | EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); | ||
222 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); | ||
223 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); | ||
224 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); | ||
225 | EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); | ||
226 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); | ||
227 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); | ||
228 | EXT4_DEPRECATED_ATTR(max_writeback_mb_bump, 128); | ||
229 | EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); | ||
230 | EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); | ||
231 | EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval); | ||
232 | EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst); | ||
233 | EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval); | ||
234 | EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst); | ||
235 | EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval); | ||
236 | EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst); | ||
237 | EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); | ||
238 | EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time); | ||
239 | EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time); | ||
240 | |||
241 | static struct attribute *ext4_attrs[] = { | ||
242 | ATTR_LIST(delayed_allocation_blocks), | ||
243 | ATTR_LIST(session_write_kbytes), | ||
244 | ATTR_LIST(lifetime_write_kbytes), | ||
245 | ATTR_LIST(reserved_clusters), | ||
246 | ATTR_LIST(inode_readahead_blks), | ||
247 | ATTR_LIST(inode_goal), | ||
248 | ATTR_LIST(mb_stats), | ||
249 | ATTR_LIST(mb_max_to_scan), | ||
250 | ATTR_LIST(mb_min_to_scan), | ||
251 | ATTR_LIST(mb_order2_req), | ||
252 | ATTR_LIST(mb_stream_req), | ||
253 | ATTR_LIST(mb_group_prealloc), | ||
254 | ATTR_LIST(max_writeback_mb_bump), | ||
255 | ATTR_LIST(extent_max_zeroout_kb), | ||
256 | ATTR_LIST(trigger_fs_error), | ||
257 | ATTR_LIST(err_ratelimit_interval_ms), | ||
258 | ATTR_LIST(err_ratelimit_burst), | ||
259 | ATTR_LIST(warning_ratelimit_interval_ms), | ||
260 | ATTR_LIST(warning_ratelimit_burst), | ||
261 | ATTR_LIST(msg_ratelimit_interval_ms), | ||
262 | ATTR_LIST(msg_ratelimit_burst), | ||
263 | ATTR_LIST(errors_count), | ||
264 | ATTR_LIST(first_error_time), | ||
265 | ATTR_LIST(last_error_time), | ||
266 | NULL, | ||
267 | }; | ||
268 | |||
269 | /* Features this copy of ext4 supports */ | ||
270 | EXT4_INFO_ATTR(lazy_itable_init); | ||
271 | EXT4_INFO_ATTR(batched_discard); | ||
272 | EXT4_INFO_ATTR(meta_bg_resize); | ||
273 | EXT4_INFO_ATTR(encryption); | ||
274 | |||
275 | static struct attribute *ext4_feat_attrs[] = { | ||
276 | ATTR_LIST(lazy_itable_init), | ||
277 | ATTR_LIST(batched_discard), | ||
278 | ATTR_LIST(meta_bg_resize), | ||
279 | ATTR_LIST(encryption), | ||
280 | NULL, | ||
281 | }; | ||
282 | |||
283 | static ssize_t ext4_attr_show(struct kobject *kobj, | ||
284 | struct attribute *attr, char *buf) | ||
285 | { | ||
286 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
287 | s_kobj); | ||
288 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
289 | |||
290 | return a->show ? a->show(a, sbi, buf) : 0; | ||
291 | } | ||
292 | |||
293 | static ssize_t ext4_attr_store(struct kobject *kobj, | ||
294 | struct attribute *attr, | ||
295 | const char *buf, size_t len) | ||
296 | { | ||
297 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
298 | s_kobj); | ||
299 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
300 | |||
301 | return a->store ? a->store(a, sbi, buf, len) : 0; | ||
302 | } | ||
303 | |||
304 | static void ext4_sb_release(struct kobject *kobj) | ||
305 | { | ||
306 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
307 | s_kobj); | ||
308 | complete(&sbi->s_kobj_unregister); | ||
309 | } | ||
310 | |||
311 | static const struct sysfs_ops ext4_attr_ops = { | ||
312 | .show = ext4_attr_show, | ||
313 | .store = ext4_attr_store, | ||
314 | }; | ||
315 | |||
316 | static struct kobj_type ext4_sb_ktype = { | ||
317 | .default_attrs = ext4_attrs, | ||
318 | .sysfs_ops = &ext4_attr_ops, | ||
319 | .release = ext4_sb_release, | ||
320 | }; | ||
321 | |||
322 | static struct kobj_type ext4_ktype = { | ||
323 | .sysfs_ops = &ext4_attr_ops, | ||
324 | }; | ||
325 | |||
326 | static struct kset ext4_kset = { | ||
327 | .kobj = {.ktype = &ext4_ktype}, | ||
328 | }; | ||
329 | |||
330 | static ssize_t ext4_feat_show(struct kobject *kobj, | ||
331 | struct attribute *attr, char *buf) | ||
332 | { | ||
333 | return snprintf(buf, PAGE_SIZE, "supported\n"); | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * We can not use ext4_attr_show/store because it relies on the kobject | ||
338 | * being embedded in the ext4_sb_info structure which is definitely not | ||
339 | * true in this case. | ||
340 | */ | ||
341 | static const struct sysfs_ops ext4_feat_ops = { | ||
342 | .show = ext4_feat_show, | ||
343 | .store = NULL, | ||
344 | }; | ||
345 | |||
346 | static struct kobj_type ext4_feat_ktype = { | ||
347 | .default_attrs = ext4_feat_attrs, | ||
348 | .sysfs_ops = &ext4_feat_ops, | ||
349 | }; | ||
350 | |||
351 | static struct kobject ext4_feat = { | ||
352 | .kset = &ext4_kset, | ||
353 | }; | ||
354 | |||
355 | int ext4_register_sysfs(struct super_block *sb) | ||
356 | { | ||
357 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
358 | |||
359 | sbi->s_kobj.kset = &ext4_kset; | ||
360 | init_completion(&sbi->s_kobj_unregister); | ||
361 | return kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, NULL, | ||
362 | "%s", sb->s_id); | ||
363 | } | ||
364 | |||
365 | int __init ext4_init_sysfs(void) | ||
366 | { | ||
367 | int ret; | ||
368 | |||
369 | kobject_set_name(&ext4_kset.kobj, "ext4"); | ||
370 | ext4_kset.kobj.parent = fs_kobj; | ||
371 | ret = kset_register(&ext4_kset); | ||
372 | if (ret) | ||
373 | return ret; | ||
374 | |||
375 | ret = kobject_init_and_add(&ext4_feat, &ext4_feat_ktype, | ||
376 | NULL, "features"); | ||
377 | if (ret) | ||
378 | kset_unregister(&ext4_kset); | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | void ext4_exit_sysfs(void) | ||
383 | { | ||
384 | kobject_put(&ext4_feat); | ||
385 | kset_unregister(&ext4_kset); | ||
386 | } | ||
387 | |||