aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-03-31 09:10:09 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-03-31 09:10:09 -0400
commit3197ebdb130473a92760100cbfe0d7e671838f48 (patch)
tree7101dc642e91026a65264adb7845ce3561d691fe
parentafc32f7ee9febc020c73da61402351d4c90437f3 (diff)
ext4: Add sysfs support
Add basic sysfs support so that information about the mounted filesystem and various tuning parameters can be accessed via /sys/fs/ext4/<dev>/*. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--Documentation/ABI/testing/sysfs-fs-ext481
-rw-r--r--fs/ext4/ext4_sb.h2
-rw-r--r--fs/ext4/super.c207
3 files changed, 290 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4
new file mode 100644
index 000000000000..4e79074de282
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-fs-ext4
@@ -0,0 +1,81 @@
1What: /sys/fs/ext4/<disk>/mb_stats
2Date: March 2008
3Contact: "Theodore Ts'o" <tytso@mit.edu>
4Description:
5 Controls whether the multiblock allocator should
6 collect statistics, which are shown during the unmount.
7 1 means to collect statistics, 0 means not to collect
8 statistics
9
10What: /sys/fs/ext4/<disk>/mb_group_prealloc
11Date: March 2008
12Contact: "Theodore Ts'o" <tytso@mit.edu>
13Description:
14 The multiblock allocator will round up allocation
15 requests to a multiple of this tuning parameter if the
16 stripe size is not set in the ext4 superblock
17
18What: /sys/fs/ext4/<disk>/mb_max_to_scan
19Date: March 2008
20Contact: "Theodore Ts'o" <tytso@mit.edu>
21Description:
22 The maximum number of extents the multiblock allocator
23 will search to find the best extent
24
25What: /sys/fs/ext4/<disk>/mb_min_to_scan
26Date: March 2008
27Contact: "Theodore Ts'o" <tytso@mit.edu>
28Description:
29 The minimum number of extents the multiblock allocator
30 will search to find the best extent
31
32What: /sys/fs/ext4/<disk>/mb_order2_req
33Date: March 2008
34Contact: "Theodore Ts'o" <tytso@mit.edu>
35Description:
36 Tuning parameter which controls the minimum size for
37 requests (as a power of 2) where the buddy cache is
38 used
39
40What: /sys/fs/ext4/<disk>/mb_stream_req
41Date: March 2008
42Contact: "Theodore Ts'o" <tytso@mit.edu>
43Description:
44 Files which have fewer blocks than this tunable
45 parameter will have their blocks allocated out of a
46 block group specific preallocation pool, so that small
47 files are packed closely together. Each large file
48 will have its blocks allocated out of its own unique
49 preallocation pool.
50
51What: /sys/fs/ext4/<disk>/inode_readahead
52Date: March 2008
53Contact: "Theodore Ts'o" <tytso@mit.edu>
54Description:
55 Tuning parameter which controls the maximum number of
56 inode table blocks that ext4's inode table readahead
57 algorithm will pre-read into the buffer cache
58
59What: /sys/fs/ext4/<disk>/delayed_allocation_blocks
60Date: March 2008
61Contact: "Theodore Ts'o" <tytso@mit.edu>
62Description:
63 This file is read-only and shows the number of blocks
64 that are dirty in the page cache, but which do not
65 have their location in the filesystem allocated yet.
66
67What: /sys/fs/ext4/<disk>/lifetime_write_kbytes
68Date: March 2008
69Contact: "Theodore Ts'o" <tytso@mit.edu>
70Description:
71 This file is read-only and shows the number of kilobytes
72 of data that have been written to this filesystem since it was
73 created.
74
75What: /sys/fs/ext4/<disk>/session_write_kbytes
76Date: March 2008
77Contact: "Theodore Ts'o" <tytso@mit.edu>
78Description:
79 This file is read-only and shows the number of
80 kilobytes of data that have been written to this
81 filesystem since it was mounted.
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h
index 50ab1169c378..57b71fefbccf 100644
--- a/fs/ext4/ext4_sb.h
+++ b/fs/ext4/ext4_sb.h
@@ -64,6 +64,8 @@ struct ext4_sb_info {
64 struct percpu_counter s_dirtyblocks_counter; 64 struct percpu_counter s_dirtyblocks_counter;
65 struct blockgroup_lock *s_blockgroup_lock; 65 struct blockgroup_lock *s_blockgroup_lock;
66 struct proc_dir_entry *s_proc; 66 struct proc_dir_entry *s_proc;
67 struct kobject s_kobj;
68 struct completion s_kobj_unregister;
67 69
68 /* Journaling */ 70 /* Journaling */
69 struct inode *s_journal_inode; 71 struct inode *s_journal_inode;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 30fc27cdf8fc..2883d4318c22 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
50struct proc_dir_entry *ext4_proc_root; 51struct proc_dir_entry *ext4_proc_root;
52static struct kset *ext4_kset;
51 53
52static int ext4_load_journal(struct super_block *, struct ext4_super_block *, 54static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
53 unsigned long journal_devnum); 55 unsigned long journal_devnum);
@@ -580,6 +582,7 @@ static void ext4_put_super(struct super_block *sb)
580 remove_proc_entry("inode_readahead_blks", sbi->s_proc); 582 remove_proc_entry("inode_readahead_blks", sbi->s_proc);
581 remove_proc_entry(sb->s_id, ext4_proc_root); 583 remove_proc_entry(sb->s_id, ext4_proc_root);
582 } 584 }
585 kobject_del(&sbi->s_kobj);
583 586
584 for (i = 0; i < sbi->s_gdb_count; i++) 587 for (i = 0; i < sbi->s_gdb_count; i++)
585 brelse(sbi->s_group_desc[i]); 588 brelse(sbi->s_group_desc[i]);
@@ -615,6 +618,16 @@ static void ext4_put_super(struct super_block *sb)
615 ext4_blkdev_remove(sbi); 618 ext4_blkdev_remove(sbi);
616 } 619 }
617 sb->s_fs_info = NULL; 620 sb->s_fs_info = NULL;
621 /*
622 * Now that we are completely done shutting down the
623 * superblock, we need to actually destroy the kobject.
624 */
625 unlock_kernel();
626 unlock_super(sb);
627 kobject_put(&sbi->s_kobj);
628 wait_for_completion(&sbi->s_kobj_unregister);
629 lock_super(sb);
630 lock_kernel();
618 kfree(sbi->s_blockgroup_lock); 631 kfree(sbi->s_blockgroup_lock);
619 kfree(sbi); 632 kfree(sbi);
620 return; 633 return;
@@ -1464,6 +1477,11 @@ set_qf_format:
1464 return 0; 1477 return 0;
1465 if (option < 0 || option > (1 << 30)) 1478 if (option < 0 || option > (1 << 30))
1466 return 0; 1479 return 0;
1480 if (option & (option - 1)) {
1481 printk(KERN_ERR "EXT4-fs: inode_readahead_blks"
1482 " must be a power of 2\n");
1483 return 0;
1484 }
1467 sbi->s_inode_readahead_blks = option; 1485 sbi->s_inode_readahead_blks = option;
1468 break; 1486 break;
1469 case Opt_journal_ioprio: 1487 case Opt_journal_ioprio:
@@ -1992,6 +2010,181 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
1992 return 0; 2010 return 0;
1993} 2011}
1994 2012
2013/* sysfs supprt */
2014
2015struct ext4_attr {
2016 struct attribute attr;
2017 ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
2018 ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *,
2019 const char *, size_t);
2020 int offset;
2021};
2022
2023static int parse_strtoul(const char *buf,
2024 unsigned long max, unsigned long *value)
2025{
2026 char *endp;
2027
2028 while (*buf && isspace(*buf))
2029 buf++;
2030 *value = simple_strtoul(buf, &endp, 0);
2031 while (*endp && isspace(*endp))
2032 endp++;
2033 if (*endp || *value > max)
2034 return -EINVAL;
2035
2036 return 0;
2037}
2038
2039static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a,
2040 struct ext4_sb_info *sbi,
2041 char *buf)
2042{
2043 return snprintf(buf, PAGE_SIZE, "%llu\n",
2044 (s64) percpu_counter_sum(&sbi->s_dirtyblocks_counter));
2045}
2046
2047static ssize_t session_write_kbytes_show(struct ext4_attr *a,
2048 struct ext4_sb_info *sbi, char *buf)
2049{
2050 struct super_block *sb = sbi->s_buddy_cache->i_sb;
2051
2052 return snprintf(buf, PAGE_SIZE, "%lu\n",
2053 (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
2054 sbi->s_sectors_written_start) >> 1);
2055}
2056
2057static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
2058 struct ext4_sb_info *sbi, char *buf)
2059{
2060 struct super_block *sb = sbi->s_buddy_cache->i_sb;
2061
2062 return snprintf(buf, PAGE_SIZE, "%llu\n",
2063 sbi->s_kbytes_written +
2064 ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
2065 EXT4_SB(sb)->s_sectors_written_start) >> 1));
2066}
2067
2068static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
2069 struct ext4_sb_info *sbi,
2070 const char *buf, size_t count)
2071{
2072 unsigned long t;
2073
2074 if (parse_strtoul(buf, 0x40000000, &t))
2075 return -EINVAL;
2076
2077 /* inode_readahead_blks must be a power of 2 */
2078 if (t & (t-1))
2079 return -EINVAL;
2080
2081 sbi->s_inode_readahead_blks = t;
2082 return count;
2083}
2084
2085static ssize_t sbi_ui_show(struct ext4_attr *a,
2086 struct ext4_sb_info *sbi, char *buf)
2087{
2088 unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
2089
2090 return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
2091}
2092
2093static ssize_t sbi_ui_store(struct ext4_attr *a,
2094 struct ext4_sb_info *sbi,
2095 const char *buf, size_t count)
2096{
2097 unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
2098 unsigned long t;
2099
2100 if (parse_strtoul(buf, 0xffffffff, &t))
2101 return -EINVAL;
2102 *ui = t;
2103 return count;
2104}
2105
2106#define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \
2107static struct ext4_attr ext4_attr_##_name = { \
2108 .attr = {.name = __stringify(_name), .mode = _mode }, \
2109 .show = _show, \
2110 .store = _store, \
2111 .offset = offsetof(struct ext4_sb_info, _elname), \
2112}
2113#define EXT4_ATTR(name, mode, show, store) \
2114static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
2115
2116#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
2117#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
2118#define EXT4_RW_ATTR_SBI_UI(name, elname) \
2119 EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname)
2120#define ATTR_LIST(name) &ext4_attr_##name.attr
2121
2122EXT4_RO_ATTR(delayed_allocation_blocks);
2123EXT4_RO_ATTR(session_write_kbytes);
2124EXT4_RO_ATTR(lifetime_write_kbytes);
2125EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
2126 inode_readahead_blks_store, s_inode_readahead_blks);
2127EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
2128EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
2129EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
2130EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
2131EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
2132EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
2133
2134static struct attribute *ext4_attrs[] = {
2135 ATTR_LIST(delayed_allocation_blocks),
2136 ATTR_LIST(session_write_kbytes),
2137 ATTR_LIST(lifetime_write_kbytes),
2138 ATTR_LIST(inode_readahead_blks),
2139 ATTR_LIST(mb_stats),
2140 ATTR_LIST(mb_max_to_scan),
2141 ATTR_LIST(mb_min_to_scan),
2142 ATTR_LIST(mb_order2_req),
2143 ATTR_LIST(mb_stream_req),
2144 ATTR_LIST(mb_group_prealloc),
2145 NULL,
2146};
2147
2148static ssize_t ext4_attr_show(struct kobject *kobj,
2149 struct attribute *attr, char *buf)
2150{
2151 struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
2152 s_kobj);
2153 struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
2154
2155 return a->show ? a->show(a, sbi, buf) : 0;
2156}
2157
2158static ssize_t ext4_attr_store(struct kobject *kobj,
2159 struct attribute *attr,
2160 const char *buf, size_t len)
2161{
2162 struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
2163 s_kobj);
2164 struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
2165
2166 return a->store ? a->store(a, sbi, buf, len) : 0;
2167}
2168
2169static void ext4_sb_release(struct kobject *kobj)
2170{
2171 struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
2172 s_kobj);
2173 complete(&sbi->s_kobj_unregister);
2174}
2175
2176
2177static struct sysfs_ops ext4_attr_ops = {
2178 .show = ext4_attr_show,
2179 .store = ext4_attr_store,
2180};
2181
2182static struct kobj_type ext4_ktype = {
2183 .default_attrs = ext4_attrs,
2184 .sysfs_ops = &ext4_attr_ops,
2185 .release = ext4_sb_release,
2186};
2187
1995static int ext4_fill_super(struct super_block *sb, void *data, int silent) 2188static int ext4_fill_super(struct super_block *sb, void *data, int silent)
1996 __releases(kernel_lock) 2189 __releases(kernel_lock)
1997 __acquires(kernel_lock) 2190 __acquires(kernel_lock)
@@ -2575,6 +2768,16 @@ no_journal:
2575 goto failed_mount4; 2768 goto failed_mount4;
2576 } 2769 }
2577 2770
2771 sbi->s_kobj.kset = ext4_kset;
2772 init_completion(&sbi->s_kobj_unregister);
2773 err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL,
2774 "%s", sb->s_id);
2775 if (err) {
2776 ext4_mb_release(sb);
2777 ext4_ext_release(sb);
2778 goto failed_mount4;
2779 };
2780
2578 /* 2781 /*
2579 * akpm: core read_super() calls in here with the superblock locked. 2782 * akpm: core read_super() calls in here with the superblock locked.
2580 * That deadlocks, because orphan cleanup needs to lock the superblock 2783 * That deadlocks, because orphan cleanup needs to lock the superblock
@@ -3734,6 +3937,9 @@ static int __init init_ext4_fs(void)
3734{ 3937{
3735 int err; 3938 int err;
3736 3939
3940 ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
3941 if (!ext4_kset)
3942 return -ENOMEM;
3737 ext4_proc_root = proc_mkdir("fs/ext4", NULL); 3943 ext4_proc_root = proc_mkdir("fs/ext4", NULL);
3738 err = init_ext4_mballoc(); 3944 err = init_ext4_mballoc();
3739 if (err) 3945 if (err)
@@ -3775,6 +3981,7 @@ static void __exit exit_ext4_fs(void)
3775 exit_ext4_xattr(); 3981 exit_ext4_xattr();
3776 exit_ext4_mballoc(); 3982 exit_ext4_mballoc();
3777 remove_proc_entry("fs/ext4", NULL); 3983 remove_proc_entry("fs/ext4", NULL);
3984 kset_unregister(ext4_kset);
3778} 3985}
3779 3986
3780MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); 3987MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");