diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-04-30 03:54:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:49 -0400 |
commit | cf0ca9fe5dd9e3693d935757a7b2fc50fc576554 (patch) | |
tree | c795c5271eda9fc67579fa3176c646b892dfdb41 /mm | |
parent | caafa4324335aeb11bc233d5f87aca8cce30beba (diff) |
mm: bdi: export BDI attributes in sysfs
Provide a place in sysfs (/sys/class/bdi) for the backing_dev_info object.
This allows us to see and set the various BDI specific variables.
In particular this properly exposes the read-ahead window for all relevant
users and /sys/block/<block>/queue/read_ahead_kb should be deprecated.
With patient help from Kay Sievers and Greg KH
[mszeredi@suse.cz]
- split off NFS and FUSE changes into separate patches
- document new sysfs attributes under Documentation/ABI
- do bdi_class_init as a core_initcall, otherwise the "default" BDI
won't be initialized
- remove bdi_init_fmt macro, it's not used very much
[akpm@linux-foundation.org: fix ia64 warning]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Acked-by: Greg KH <greg@kroah.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/backing-dev.c | 119 | ||||
-rw-r--r-- | mm/page-writeback.c | 2 | ||||
-rw-r--r-- | mm/readahead.c | 8 |
3 files changed, 127 insertions, 2 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index e8644b1e5527..847eabe4824c 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -4,12 +4,129 @@ | |||
4 | #include <linux/fs.h> | 4 | #include <linux/fs.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/writeback.h> | ||
8 | #include <linux/device.h> | ||
9 | |||
10 | |||
11 | static struct class *bdi_class; | ||
12 | |||
13 | static ssize_t read_ahead_kb_store(struct device *dev, | ||
14 | struct device_attribute *attr, | ||
15 | const char *buf, size_t count) | ||
16 | { | ||
17 | struct backing_dev_info *bdi = dev_get_drvdata(dev); | ||
18 | char *end; | ||
19 | unsigned long read_ahead_kb; | ||
20 | ssize_t ret = -EINVAL; | ||
21 | |||
22 | read_ahead_kb = simple_strtoul(buf, &end, 10); | ||
23 | if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) { | ||
24 | bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10); | ||
25 | ret = count; | ||
26 | } | ||
27 | return ret; | ||
28 | } | ||
29 | |||
30 | #define K(pages) ((pages) << (PAGE_SHIFT - 10)) | ||
31 | |||
32 | #define BDI_SHOW(name, expr) \ | ||
33 | static ssize_t name##_show(struct device *dev, \ | ||
34 | struct device_attribute *attr, char *page) \ | ||
35 | { \ | ||
36 | struct backing_dev_info *bdi = dev_get_drvdata(dev); \ | ||
37 | \ | ||
38 | return snprintf(page, PAGE_SIZE-1, "%lld\n", (long long)expr); \ | ||
39 | } | ||
40 | |||
41 | BDI_SHOW(read_ahead_kb, K(bdi->ra_pages)) | ||
42 | |||
43 | BDI_SHOW(reclaimable_kb, K(bdi_stat(bdi, BDI_RECLAIMABLE))) | ||
44 | BDI_SHOW(writeback_kb, K(bdi_stat(bdi, BDI_WRITEBACK))) | ||
45 | |||
46 | static inline unsigned long get_dirty(struct backing_dev_info *bdi, int i) | ||
47 | { | ||
48 | unsigned long thresh[3]; | ||
49 | |||
50 | get_dirty_limits(&thresh[0], &thresh[1], &thresh[2], bdi); | ||
51 | |||
52 | return thresh[i]; | ||
53 | } | ||
54 | |||
55 | BDI_SHOW(dirty_kb, K(get_dirty(bdi, 1))) | ||
56 | BDI_SHOW(bdi_dirty_kb, K(get_dirty(bdi, 2))) | ||
57 | |||
58 | #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store) | ||
59 | |||
60 | static struct device_attribute bdi_dev_attrs[] = { | ||
61 | __ATTR_RW(read_ahead_kb), | ||
62 | __ATTR_RO(reclaimable_kb), | ||
63 | __ATTR_RO(writeback_kb), | ||
64 | __ATTR_RO(dirty_kb), | ||
65 | __ATTR_RO(bdi_dirty_kb), | ||
66 | __ATTR_NULL, | ||
67 | }; | ||
68 | |||
69 | static __init int bdi_class_init(void) | ||
70 | { | ||
71 | bdi_class = class_create(THIS_MODULE, "bdi"); | ||
72 | bdi_class->dev_attrs = bdi_dev_attrs; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | core_initcall(bdi_class_init); | ||
77 | |||
78 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, | ||
79 | const char *fmt, ...) | ||
80 | { | ||
81 | char *name; | ||
82 | va_list args; | ||
83 | int ret = 0; | ||
84 | struct device *dev; | ||
85 | |||
86 | va_start(args, fmt); | ||
87 | name = kvasprintf(GFP_KERNEL, fmt, args); | ||
88 | va_end(args); | ||
89 | |||
90 | if (!name) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | dev = device_create(bdi_class, parent, MKDEV(0, 0), name); | ||
94 | if (IS_ERR(dev)) { | ||
95 | ret = PTR_ERR(dev); | ||
96 | goto exit; | ||
97 | } | ||
98 | |||
99 | bdi->dev = dev; | ||
100 | dev_set_drvdata(bdi->dev, bdi); | ||
101 | |||
102 | exit: | ||
103 | kfree(name); | ||
104 | return ret; | ||
105 | } | ||
106 | EXPORT_SYMBOL(bdi_register); | ||
107 | |||
108 | int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) | ||
109 | { | ||
110 | return bdi_register(bdi, NULL, "%u:%u", MAJOR(dev), MINOR(dev)); | ||
111 | } | ||
112 | EXPORT_SYMBOL(bdi_register_dev); | ||
113 | |||
114 | void bdi_unregister(struct backing_dev_info *bdi) | ||
115 | { | ||
116 | if (bdi->dev) { | ||
117 | device_unregister(bdi->dev); | ||
118 | bdi->dev = NULL; | ||
119 | } | ||
120 | } | ||
121 | EXPORT_SYMBOL(bdi_unregister); | ||
7 | 122 | ||
8 | int bdi_init(struct backing_dev_info *bdi) | 123 | int bdi_init(struct backing_dev_info *bdi) |
9 | { | 124 | { |
10 | int i; | 125 | int i; |
11 | int err; | 126 | int err; |
12 | 127 | ||
128 | bdi->dev = NULL; | ||
129 | |||
13 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) { | 130 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) { |
14 | err = percpu_counter_init_irq(&bdi->bdi_stat[i], 0); | 131 | err = percpu_counter_init_irq(&bdi->bdi_stat[i], 0); |
15 | if (err) | 132 | if (err) |
@@ -33,6 +150,8 @@ void bdi_destroy(struct backing_dev_info *bdi) | |||
33 | { | 150 | { |
34 | int i; | 151 | int i; |
35 | 152 | ||
153 | bdi_unregister(bdi); | ||
154 | |||
36 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) | 155 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) |
37 | percpu_counter_destroy(&bdi->bdi_stat[i]); | 156 | percpu_counter_destroy(&bdi->bdi_stat[i]); |
38 | 157 | ||
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 5e00f1772c20..e5b6b1190a95 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -300,7 +300,7 @@ static unsigned long determine_dirtyable_memory(void) | |||
300 | return x + 1; /* Ensure that we never return 0 */ | 300 | return x + 1; /* Ensure that we never return 0 */ |
301 | } | 301 | } |
302 | 302 | ||
303 | static void | 303 | void |
304 | get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty, | 304 | get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty, |
305 | struct backing_dev_info *bdi) | 305 | struct backing_dev_info *bdi) |
306 | { | 306 | { |
diff --git a/mm/readahead.c b/mm/readahead.c index 8762e8988972..d8723a5f6496 100644 --- a/mm/readahead.c +++ b/mm/readahead.c | |||
@@ -235,7 +235,13 @@ unsigned long max_sane_readahead(unsigned long nr) | |||
235 | 235 | ||
236 | static int __init readahead_init(void) | 236 | static int __init readahead_init(void) |
237 | { | 237 | { |
238 | return bdi_init(&default_backing_dev_info); | 238 | int err; |
239 | |||
240 | err = bdi_init(&default_backing_dev_info); | ||
241 | if (!err) | ||
242 | bdi_register(&default_backing_dev_info, NULL, "default"); | ||
243 | |||
244 | return err; | ||
239 | } | 245 | } |
240 | subsys_initcall(readahead_init); | 246 | subsys_initcall(readahead_init); |
241 | 247 | ||