diff options
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 327 |
1 files changed, 260 insertions, 67 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f7371a6a923d..9987bba99db3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/quotaops.h> | 35 | #include <linux/quotaops.h> |
36 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
38 | #include <linux/ctype.h> | ||
38 | #include <linux/marker.h> | 39 | #include <linux/marker.h> |
39 | #include <linux/log2.h> | 40 | #include <linux/log2.h> |
40 | #include <linux/crc16.h> | 41 | #include <linux/crc16.h> |
@@ -48,6 +49,7 @@ | |||
48 | #include "group.h" | 49 | #include "group.h" |
49 | 50 | ||
50 | struct proc_dir_entry *ext4_proc_root; | 51 | struct proc_dir_entry *ext4_proc_root; |
52 | static struct kset *ext4_kset; | ||
51 | 53 | ||
52 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, | 54 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, |
53 | unsigned long journal_devnum); | 55 | unsigned long journal_devnum); |
@@ -577,9 +579,9 @@ static void ext4_put_super(struct super_block *sb) | |||
577 | ext4_commit_super(sb, es, 1); | 579 | ext4_commit_super(sb, es, 1); |
578 | } | 580 | } |
579 | if (sbi->s_proc) { | 581 | if (sbi->s_proc) { |
580 | remove_proc_entry("inode_readahead_blks", sbi->s_proc); | ||
581 | remove_proc_entry(sb->s_id, ext4_proc_root); | 582 | remove_proc_entry(sb->s_id, ext4_proc_root); |
582 | } | 583 | } |
584 | kobject_del(&sbi->s_kobj); | ||
583 | 585 | ||
584 | for (i = 0; i < sbi->s_gdb_count; i++) | 586 | for (i = 0; i < sbi->s_gdb_count; i++) |
585 | brelse(sbi->s_group_desc[i]); | 587 | brelse(sbi->s_group_desc[i]); |
@@ -615,6 +617,17 @@ static void ext4_put_super(struct super_block *sb) | |||
615 | ext4_blkdev_remove(sbi); | 617 | ext4_blkdev_remove(sbi); |
616 | } | 618 | } |
617 | sb->s_fs_info = NULL; | 619 | sb->s_fs_info = NULL; |
620 | /* | ||
621 | * Now that we are completely done shutting down the | ||
622 | * superblock, we need to actually destroy the kobject. | ||
623 | */ | ||
624 | unlock_kernel(); | ||
625 | unlock_super(sb); | ||
626 | kobject_put(&sbi->s_kobj); | ||
627 | wait_for_completion(&sbi->s_kobj_unregister); | ||
628 | lock_super(sb); | ||
629 | lock_kernel(); | ||
630 | kfree(sbi->s_blockgroup_lock); | ||
618 | kfree(sbi); | 631 | kfree(sbi); |
619 | return; | 632 | return; |
620 | } | 633 | } |
@@ -803,8 +816,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
803 | if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) | 816 | if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) |
804 | seq_puts(seq, ",noacl"); | 817 | seq_puts(seq, ",noacl"); |
805 | #endif | 818 | #endif |
806 | if (!test_opt(sb, RESERVATION)) | ||
807 | seq_puts(seq, ",noreservation"); | ||
808 | if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { | 819 | if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { |
809 | seq_printf(seq, ",commit=%u", | 820 | seq_printf(seq, ",commit=%u", |
810 | (unsigned) (sbi->s_commit_interval / HZ)); | 821 | (unsigned) (sbi->s_commit_interval / HZ)); |
@@ -855,6 +866,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
855 | if (test_opt(sb, DATA_ERR_ABORT)) | 866 | if (test_opt(sb, DATA_ERR_ABORT)) |
856 | seq_puts(seq, ",data_err=abort"); | 867 | seq_puts(seq, ",data_err=abort"); |
857 | 868 | ||
869 | if (test_opt(sb, NO_AUTO_DA_ALLOC)) | ||
870 | seq_puts(seq, ",noauto_da_alloc"); | ||
871 | |||
858 | ext4_show_quota_options(seq, sb); | 872 | ext4_show_quota_options(seq, sb); |
859 | return 0; | 873 | return 0; |
860 | } | 874 | } |
@@ -1004,7 +1018,7 @@ enum { | |||
1004 | Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, | 1018 | Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, |
1005 | Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov, | 1019 | Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov, |
1006 | Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, | 1020 | Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, |
1007 | Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, | 1021 | Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh, |
1008 | Opt_commit, Opt_min_batch_time, Opt_max_batch_time, | 1022 | Opt_commit, Opt_min_batch_time, Opt_max_batch_time, |
1009 | Opt_journal_update, Opt_journal_dev, | 1023 | Opt_journal_update, Opt_journal_dev, |
1010 | Opt_journal_checksum, Opt_journal_async_commit, | 1024 | Opt_journal_checksum, Opt_journal_async_commit, |
@@ -1012,8 +1026,8 @@ enum { | |||
1012 | Opt_data_err_abort, Opt_data_err_ignore, | 1026 | Opt_data_err_abort, Opt_data_err_ignore, |
1013 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, | 1027 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, |
1014 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, | 1028 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, |
1015 | Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, | 1029 | Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize, |
1016 | Opt_grpquota, Opt_i_version, | 1030 | Opt_usrquota, Opt_grpquota, Opt_i_version, |
1017 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, | 1031 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, |
1018 | Opt_inode_readahead_blks, Opt_journal_ioprio | 1032 | Opt_inode_readahead_blks, Opt_journal_ioprio |
1019 | }; | 1033 | }; |
@@ -1039,8 +1053,6 @@ static const match_table_t tokens = { | |||
1039 | {Opt_nouser_xattr, "nouser_xattr"}, | 1053 | {Opt_nouser_xattr, "nouser_xattr"}, |
1040 | {Opt_acl, "acl"}, | 1054 | {Opt_acl, "acl"}, |
1041 | {Opt_noacl, "noacl"}, | 1055 | {Opt_noacl, "noacl"}, |
1042 | {Opt_reservation, "reservation"}, | ||
1043 | {Opt_noreservation, "noreservation"}, | ||
1044 | {Opt_noload, "noload"}, | 1056 | {Opt_noload, "noload"}, |
1045 | {Opt_nobh, "nobh"}, | 1057 | {Opt_nobh, "nobh"}, |
1046 | {Opt_bh, "bh"}, | 1058 | {Opt_bh, "bh"}, |
@@ -1068,6 +1080,8 @@ static const match_table_t tokens = { | |||
1068 | {Opt_quota, "quota"}, | 1080 | {Opt_quota, "quota"}, |
1069 | {Opt_usrquota, "usrquota"}, | 1081 | {Opt_usrquota, "usrquota"}, |
1070 | {Opt_barrier, "barrier=%u"}, | 1082 | {Opt_barrier, "barrier=%u"}, |
1083 | {Opt_barrier, "barrier"}, | ||
1084 | {Opt_nobarrier, "nobarrier"}, | ||
1071 | {Opt_i_version, "i_version"}, | 1085 | {Opt_i_version, "i_version"}, |
1072 | {Opt_stripe, "stripe=%u"}, | 1086 | {Opt_stripe, "stripe=%u"}, |
1073 | {Opt_resize, "resize"}, | 1087 | {Opt_resize, "resize"}, |
@@ -1075,6 +1089,9 @@ static const match_table_t tokens = { | |||
1075 | {Opt_nodelalloc, "nodelalloc"}, | 1089 | {Opt_nodelalloc, "nodelalloc"}, |
1076 | {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, | 1090 | {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, |
1077 | {Opt_journal_ioprio, "journal_ioprio=%u"}, | 1091 | {Opt_journal_ioprio, "journal_ioprio=%u"}, |
1092 | {Opt_auto_da_alloc, "auto_da_alloc=%u"}, | ||
1093 | {Opt_auto_da_alloc, "auto_da_alloc"}, | ||
1094 | {Opt_noauto_da_alloc, "noauto_da_alloc"}, | ||
1078 | {Opt_err, NULL}, | 1095 | {Opt_err, NULL}, |
1079 | }; | 1096 | }; |
1080 | 1097 | ||
@@ -1207,12 +1224,6 @@ static int parse_options(char *options, struct super_block *sb, | |||
1207 | "not supported\n"); | 1224 | "not supported\n"); |
1208 | break; | 1225 | break; |
1209 | #endif | 1226 | #endif |
1210 | case Opt_reservation: | ||
1211 | set_opt(sbi->s_mount_opt, RESERVATION); | ||
1212 | break; | ||
1213 | case Opt_noreservation: | ||
1214 | clear_opt(sbi->s_mount_opt, RESERVATION); | ||
1215 | break; | ||
1216 | case Opt_journal_update: | 1227 | case Opt_journal_update: |
1217 | /* @@@ FIXME */ | 1228 | /* @@@ FIXME */ |
1218 | /* Eventually we will want to be able to create | 1229 | /* Eventually we will want to be able to create |
@@ -1415,9 +1426,14 @@ set_qf_format: | |||
1415 | case Opt_abort: | 1426 | case Opt_abort: |
1416 | set_opt(sbi->s_mount_opt, ABORT); | 1427 | set_opt(sbi->s_mount_opt, ABORT); |
1417 | break; | 1428 | break; |
1429 | case Opt_nobarrier: | ||
1430 | clear_opt(sbi->s_mount_opt, BARRIER); | ||
1431 | break; | ||
1418 | case Opt_barrier: | 1432 | case Opt_barrier: |
1419 | if (match_int(&args[0], &option)) | 1433 | if (match_int(&args[0], &option)) { |
1420 | return 0; | 1434 | set_opt(sbi->s_mount_opt, BARRIER); |
1435 | break; | ||
1436 | } | ||
1421 | if (option) | 1437 | if (option) |
1422 | set_opt(sbi->s_mount_opt, BARRIER); | 1438 | set_opt(sbi->s_mount_opt, BARRIER); |
1423 | else | 1439 | else |
@@ -1463,6 +1479,11 @@ set_qf_format: | |||
1463 | return 0; | 1479 | return 0; |
1464 | if (option < 0 || option > (1 << 30)) | 1480 | if (option < 0 || option > (1 << 30)) |
1465 | return 0; | 1481 | return 0; |
1482 | if (option & (option - 1)) { | ||
1483 | printk(KERN_ERR "EXT4-fs: inode_readahead_blks" | ||
1484 | " must be a power of 2\n"); | ||
1485 | return 0; | ||
1486 | } | ||
1466 | sbi->s_inode_readahead_blks = option; | 1487 | sbi->s_inode_readahead_blks = option; |
1467 | break; | 1488 | break; |
1468 | case Opt_journal_ioprio: | 1489 | case Opt_journal_ioprio: |
@@ -1473,6 +1494,19 @@ set_qf_format: | |||
1473 | *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, | 1494 | *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, |
1474 | option); | 1495 | option); |
1475 | break; | 1496 | break; |
1497 | case Opt_noauto_da_alloc: | ||
1498 | set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); | ||
1499 | break; | ||
1500 | case Opt_auto_da_alloc: | ||
1501 | if (match_int(&args[0], &option)) { | ||
1502 | clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC); | ||
1503 | break; | ||
1504 | } | ||
1505 | if (option) | ||
1506 | clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC); | ||
1507 | else | ||
1508 | set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); | ||
1509 | break; | ||
1476 | default: | 1510 | default: |
1477 | printk(KERN_ERR | 1511 | printk(KERN_ERR |
1478 | "EXT4-fs: Unrecognized mount option \"%s\" " | 1512 | "EXT4-fs: Unrecognized mount option \"%s\" " |
@@ -1612,10 +1646,12 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
1612 | gdp = ext4_get_group_desc(sb, i, &bh); | 1646 | gdp = ext4_get_group_desc(sb, i, &bh); |
1613 | 1647 | ||
1614 | flex_group = ext4_flex_group(sbi, i); | 1648 | flex_group = ext4_flex_group(sbi, i); |
1615 | sbi->s_flex_groups[flex_group].free_inodes += | 1649 | atomic_set(&sbi->s_flex_groups[flex_group].free_inodes, |
1616 | ext4_free_inodes_count(sb, gdp); | 1650 | ext4_free_inodes_count(sb, gdp)); |
1617 | sbi->s_flex_groups[flex_group].free_blocks += | 1651 | atomic_set(&sbi->s_flex_groups[flex_group].free_blocks, |
1618 | ext4_free_blks_count(sb, gdp); | 1652 | ext4_free_blks_count(sb, gdp)); |
1653 | atomic_set(&sbi->s_flex_groups[flex_group].used_dirs, | ||
1654 | ext4_used_dirs_count(sb, gdp)); | ||
1619 | } | 1655 | } |
1620 | 1656 | ||
1621 | return 1; | 1657 | return 1; |
@@ -1991,6 +2027,181 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) | |||
1991 | return 0; | 2027 | return 0; |
1992 | } | 2028 | } |
1993 | 2029 | ||
2030 | /* sysfs supprt */ | ||
2031 | |||
2032 | struct ext4_attr { | ||
2033 | struct attribute attr; | ||
2034 | ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *); | ||
2035 | ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, | ||
2036 | const char *, size_t); | ||
2037 | int offset; | ||
2038 | }; | ||
2039 | |||
2040 | static int parse_strtoul(const char *buf, | ||
2041 | unsigned long max, unsigned long *value) | ||
2042 | { | ||
2043 | char *endp; | ||
2044 | |||
2045 | while (*buf && isspace(*buf)) | ||
2046 | buf++; | ||
2047 | *value = simple_strtoul(buf, &endp, 0); | ||
2048 | while (*endp && isspace(*endp)) | ||
2049 | endp++; | ||
2050 | if (*endp || *value > max) | ||
2051 | return -EINVAL; | ||
2052 | |||
2053 | return 0; | ||
2054 | } | ||
2055 | |||
2056 | static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a, | ||
2057 | struct ext4_sb_info *sbi, | ||
2058 | char *buf) | ||
2059 | { | ||
2060 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
2061 | (s64) percpu_counter_sum(&sbi->s_dirtyblocks_counter)); | ||
2062 | } | ||
2063 | |||
2064 | static ssize_t session_write_kbytes_show(struct ext4_attr *a, | ||
2065 | struct ext4_sb_info *sbi, char *buf) | ||
2066 | { | ||
2067 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
2068 | |||
2069 | return snprintf(buf, PAGE_SIZE, "%lu\n", | ||
2070 | (part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
2071 | sbi->s_sectors_written_start) >> 1); | ||
2072 | } | ||
2073 | |||
2074 | static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a, | ||
2075 | struct ext4_sb_info *sbi, char *buf) | ||
2076 | { | ||
2077 | struct super_block *sb = sbi->s_buddy_cache->i_sb; | ||
2078 | |||
2079 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
2080 | sbi->s_kbytes_written + | ||
2081 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
2082 | EXT4_SB(sb)->s_sectors_written_start) >> 1)); | ||
2083 | } | ||
2084 | |||
2085 | static ssize_t inode_readahead_blks_store(struct ext4_attr *a, | ||
2086 | struct ext4_sb_info *sbi, | ||
2087 | const char *buf, size_t count) | ||
2088 | { | ||
2089 | unsigned long t; | ||
2090 | |||
2091 | if (parse_strtoul(buf, 0x40000000, &t)) | ||
2092 | return -EINVAL; | ||
2093 | |||
2094 | /* inode_readahead_blks must be a power of 2 */ | ||
2095 | if (t & (t-1)) | ||
2096 | return -EINVAL; | ||
2097 | |||
2098 | sbi->s_inode_readahead_blks = t; | ||
2099 | return count; | ||
2100 | } | ||
2101 | |||
2102 | static ssize_t sbi_ui_show(struct ext4_attr *a, | ||
2103 | struct ext4_sb_info *sbi, char *buf) | ||
2104 | { | ||
2105 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset); | ||
2106 | |||
2107 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | ||
2108 | } | ||
2109 | |||
2110 | static ssize_t sbi_ui_store(struct ext4_attr *a, | ||
2111 | struct ext4_sb_info *sbi, | ||
2112 | const char *buf, size_t count) | ||
2113 | { | ||
2114 | unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset); | ||
2115 | unsigned long t; | ||
2116 | |||
2117 | if (parse_strtoul(buf, 0xffffffff, &t)) | ||
2118 | return -EINVAL; | ||
2119 | *ui = t; | ||
2120 | return count; | ||
2121 | } | ||
2122 | |||
2123 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ | ||
2124 | static struct ext4_attr ext4_attr_##_name = { \ | ||
2125 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
2126 | .show = _show, \ | ||
2127 | .store = _store, \ | ||
2128 | .offset = offsetof(struct ext4_sb_info, _elname), \ | ||
2129 | } | ||
2130 | #define EXT4_ATTR(name, mode, show, store) \ | ||
2131 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) | ||
2132 | |||
2133 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) | ||
2134 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) | ||
2135 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ | ||
2136 | EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname) | ||
2137 | #define ATTR_LIST(name) &ext4_attr_##name.attr | ||
2138 | |||
2139 | EXT4_RO_ATTR(delayed_allocation_blocks); | ||
2140 | EXT4_RO_ATTR(session_write_kbytes); | ||
2141 | EXT4_RO_ATTR(lifetime_write_kbytes); | ||
2142 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, | ||
2143 | inode_readahead_blks_store, s_inode_readahead_blks); | ||
2144 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); | ||
2145 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); | ||
2146 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); | ||
2147 | EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); | ||
2148 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); | ||
2149 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); | ||
2150 | |||
2151 | static struct attribute *ext4_attrs[] = { | ||
2152 | ATTR_LIST(delayed_allocation_blocks), | ||
2153 | ATTR_LIST(session_write_kbytes), | ||
2154 | ATTR_LIST(lifetime_write_kbytes), | ||
2155 | ATTR_LIST(inode_readahead_blks), | ||
2156 | ATTR_LIST(mb_stats), | ||
2157 | ATTR_LIST(mb_max_to_scan), | ||
2158 | ATTR_LIST(mb_min_to_scan), | ||
2159 | ATTR_LIST(mb_order2_req), | ||
2160 | ATTR_LIST(mb_stream_req), | ||
2161 | ATTR_LIST(mb_group_prealloc), | ||
2162 | NULL, | ||
2163 | }; | ||
2164 | |||
2165 | static ssize_t ext4_attr_show(struct kobject *kobj, | ||
2166 | struct attribute *attr, char *buf) | ||
2167 | { | ||
2168 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2169 | s_kobj); | ||
2170 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
2171 | |||
2172 | return a->show ? a->show(a, sbi, buf) : 0; | ||
2173 | } | ||
2174 | |||
2175 | static ssize_t ext4_attr_store(struct kobject *kobj, | ||
2176 | struct attribute *attr, | ||
2177 | const char *buf, size_t len) | ||
2178 | { | ||
2179 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2180 | s_kobj); | ||
2181 | struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); | ||
2182 | |||
2183 | return a->store ? a->store(a, sbi, buf, len) : 0; | ||
2184 | } | ||
2185 | |||
2186 | static void ext4_sb_release(struct kobject *kobj) | ||
2187 | { | ||
2188 | struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, | ||
2189 | s_kobj); | ||
2190 | complete(&sbi->s_kobj_unregister); | ||
2191 | } | ||
2192 | |||
2193 | |||
2194 | static struct sysfs_ops ext4_attr_ops = { | ||
2195 | .show = ext4_attr_show, | ||
2196 | .store = ext4_attr_store, | ||
2197 | }; | ||
2198 | |||
2199 | static struct kobj_type ext4_ktype = { | ||
2200 | .default_attrs = ext4_attrs, | ||
2201 | .sysfs_ops = &ext4_attr_ops, | ||
2202 | .release = ext4_sb_release, | ||
2203 | }; | ||
2204 | |||
1994 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 2205 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
1995 | __releases(kernel_lock) | 2206 | __releases(kernel_lock) |
1996 | __acquires(kernel_lock) | 2207 | __acquires(kernel_lock) |
@@ -2021,12 +2232,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2021 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | 2232 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
2022 | if (!sbi) | 2233 | if (!sbi) |
2023 | return -ENOMEM; | 2234 | return -ENOMEM; |
2235 | |||
2236 | sbi->s_blockgroup_lock = | ||
2237 | kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); | ||
2238 | if (!sbi->s_blockgroup_lock) { | ||
2239 | kfree(sbi); | ||
2240 | return -ENOMEM; | ||
2241 | } | ||
2024 | sb->s_fs_info = sbi; | 2242 | sb->s_fs_info = sbi; |
2025 | sbi->s_mount_opt = 0; | 2243 | sbi->s_mount_opt = 0; |
2026 | sbi->s_resuid = EXT4_DEF_RESUID; | 2244 | sbi->s_resuid = EXT4_DEF_RESUID; |
2027 | sbi->s_resgid = EXT4_DEF_RESGID; | 2245 | sbi->s_resgid = EXT4_DEF_RESGID; |
2028 | sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; | 2246 | sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; |
2029 | sbi->s_sb_block = sb_block; | 2247 | sbi->s_sb_block = sb_block; |
2248 | sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part, | ||
2249 | sectors[1]); | ||
2030 | 2250 | ||
2031 | unlock_kernel(); | 2251 | unlock_kernel(); |
2032 | 2252 | ||
@@ -2064,6 +2284,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2064 | sb->s_magic = le16_to_cpu(es->s_magic); | 2284 | sb->s_magic = le16_to_cpu(es->s_magic); |
2065 | if (sb->s_magic != EXT4_SUPER_MAGIC) | 2285 | if (sb->s_magic != EXT4_SUPER_MAGIC) |
2066 | goto cantfind_ext4; | 2286 | goto cantfind_ext4; |
2287 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); | ||
2067 | 2288 | ||
2068 | /* Set defaults before we parse the mount options */ | 2289 | /* Set defaults before we parse the mount options */ |
2069 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 2290 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
@@ -2101,7 +2322,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2101 | sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; | 2322 | sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; |
2102 | sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; | 2323 | sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; |
2103 | 2324 | ||
2104 | set_opt(sbi->s_mount_opt, RESERVATION); | ||
2105 | set_opt(sbi->s_mount_opt, BARRIER); | 2325 | set_opt(sbi->s_mount_opt, BARRIER); |
2106 | 2326 | ||
2107 | /* | 2327 | /* |
@@ -2325,14 +2545,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2325 | #ifdef CONFIG_PROC_FS | 2545 | #ifdef CONFIG_PROC_FS |
2326 | if (ext4_proc_root) | 2546 | if (ext4_proc_root) |
2327 | sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); | 2547 | sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); |
2328 | |||
2329 | if (sbi->s_proc) | ||
2330 | proc_create_data("inode_readahead_blks", 0644, sbi->s_proc, | ||
2331 | &ext4_ui_proc_fops, | ||
2332 | &sbi->s_inode_readahead_blks); | ||
2333 | #endif | 2548 | #endif |
2334 | 2549 | ||
2335 | bgl_lock_init(&sbi->s_blockgroup_lock); | 2550 | bgl_lock_init(sbi->s_blockgroup_lock); |
2336 | 2551 | ||
2337 | for (i = 0; i < db_count; i++) { | 2552 | for (i = 0; i < db_count; i++) { |
2338 | block = descriptor_loc(sb, logical_sb_block, i); | 2553 | block = descriptor_loc(sb, logical_sb_block, i); |
@@ -2564,6 +2779,16 @@ no_journal: | |||
2564 | goto failed_mount4; | 2779 | goto failed_mount4; |
2565 | } | 2780 | } |
2566 | 2781 | ||
2782 | sbi->s_kobj.kset = ext4_kset; | ||
2783 | init_completion(&sbi->s_kobj_unregister); | ||
2784 | err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL, | ||
2785 | "%s", sb->s_id); | ||
2786 | if (err) { | ||
2787 | ext4_mb_release(sb); | ||
2788 | ext4_ext_release(sb); | ||
2789 | goto failed_mount4; | ||
2790 | }; | ||
2791 | |||
2567 | /* | 2792 | /* |
2568 | * akpm: core read_super() calls in here with the superblock locked. | 2793 | * akpm: core read_super() calls in here with the superblock locked. |
2569 | * That deadlocks, because orphan cleanup needs to lock the superblock | 2794 | * That deadlocks, because orphan cleanup needs to lock the superblock |
@@ -2618,7 +2843,6 @@ failed_mount2: | |||
2618 | kfree(sbi->s_group_desc); | 2843 | kfree(sbi->s_group_desc); |
2619 | failed_mount: | 2844 | failed_mount: |
2620 | if (sbi->s_proc) { | 2845 | if (sbi->s_proc) { |
2621 | remove_proc_entry("inode_readahead_blks", sbi->s_proc); | ||
2622 | remove_proc_entry(sb->s_id, ext4_proc_root); | 2846 | remove_proc_entry(sb->s_id, ext4_proc_root); |
2623 | } | 2847 | } |
2624 | #ifdef CONFIG_QUOTA | 2848 | #ifdef CONFIG_QUOTA |
@@ -2913,6 +3137,10 @@ static int ext4_commit_super(struct super_block *sb, | |||
2913 | set_buffer_uptodate(sbh); | 3137 | set_buffer_uptodate(sbh); |
2914 | } | 3138 | } |
2915 | es->s_wtime = cpu_to_le32(get_seconds()); | 3139 | es->s_wtime = cpu_to_le32(get_seconds()); |
3140 | es->s_kbytes_written = | ||
3141 | cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + | ||
3142 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | ||
3143 | EXT4_SB(sb)->s_sectors_written_start) >> 1)); | ||
2916 | ext4_free_blocks_count_set(es, percpu_counter_sum_positive( | 3144 | ext4_free_blocks_count_set(es, percpu_counter_sum_positive( |
2917 | &EXT4_SB(sb)->s_freeblocks_counter)); | 3145 | &EXT4_SB(sb)->s_freeblocks_counter)); |
2918 | es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive( | 3146 | es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive( |
@@ -3647,45 +3875,6 @@ static int ext4_get_sb(struct file_system_type *fs_type, | |||
3647 | return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt); | 3875 | return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt); |
3648 | } | 3876 | } |
3649 | 3877 | ||
3650 | #ifdef CONFIG_PROC_FS | ||
3651 | static int ext4_ui_proc_show(struct seq_file *m, void *v) | ||
3652 | { | ||
3653 | unsigned int *p = m->private; | ||
3654 | |||
3655 | seq_printf(m, "%u\n", *p); | ||
3656 | return 0; | ||
3657 | } | ||
3658 | |||
3659 | static int ext4_ui_proc_open(struct inode *inode, struct file *file) | ||
3660 | { | ||
3661 | return single_open(file, ext4_ui_proc_show, PDE(inode)->data); | ||
3662 | } | ||
3663 | |||
3664 | static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf, | ||
3665 | size_t cnt, loff_t *ppos) | ||
3666 | { | ||
3667 | unsigned long *p = PDE(file->f_path.dentry->d_inode)->data; | ||
3668 | char str[32]; | ||
3669 | |||
3670 | if (cnt >= sizeof(str)) | ||
3671 | return -EINVAL; | ||
3672 | if (copy_from_user(str, buf, cnt)) | ||
3673 | return -EFAULT; | ||
3674 | |||
3675 | *p = simple_strtoul(str, NULL, 0); | ||
3676 | return cnt; | ||
3677 | } | ||
3678 | |||
3679 | const struct file_operations ext4_ui_proc_fops = { | ||
3680 | .owner = THIS_MODULE, | ||
3681 | .open = ext4_ui_proc_open, | ||
3682 | .read = seq_read, | ||
3683 | .llseek = seq_lseek, | ||
3684 | .release = single_release, | ||
3685 | .write = ext4_ui_proc_write, | ||
3686 | }; | ||
3687 | #endif | ||
3688 | |||
3689 | static struct file_system_type ext4_fs_type = { | 3878 | static struct file_system_type ext4_fs_type = { |
3690 | .owner = THIS_MODULE, | 3879 | .owner = THIS_MODULE, |
3691 | .name = "ext4", | 3880 | .name = "ext4", |
@@ -3719,6 +3908,9 @@ static int __init init_ext4_fs(void) | |||
3719 | { | 3908 | { |
3720 | int err; | 3909 | int err; |
3721 | 3910 | ||
3911 | ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj); | ||
3912 | if (!ext4_kset) | ||
3913 | return -ENOMEM; | ||
3722 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); | 3914 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); |
3723 | err = init_ext4_mballoc(); | 3915 | err = init_ext4_mballoc(); |
3724 | if (err) | 3916 | if (err) |
@@ -3760,6 +3952,7 @@ static void __exit exit_ext4_fs(void) | |||
3760 | exit_ext4_xattr(); | 3952 | exit_ext4_xattr(); |
3761 | exit_ext4_mballoc(); | 3953 | exit_ext4_mballoc(); |
3762 | remove_proc_entry("fs/ext4", NULL); | 3954 | remove_proc_entry("fs/ext4", NULL); |
3955 | kset_unregister(ext4_kset); | ||
3763 | } | 3956 | } |
3764 | 3957 | ||
3765 | MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); | 3958 | MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); |