diff options
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r-- | mm/backing-dev.c | 119 |
1 files changed, 119 insertions, 0 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 | ||