diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-bdi | 43 | ||||
-rw-r--r-- | include/linux/backing-dev.h | 6 | ||||
-rw-r--r-- | mm/backing-dev.c | 98 |
3 files changed, 99 insertions, 48 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-bdi b/Documentation/ABI/testing/sysfs-class-bdi index c55e811ca180..5ac1e01bbd48 100644 --- a/Documentation/ABI/testing/sysfs-class-bdi +++ b/Documentation/ABI/testing/sysfs-class-bdi | |||
@@ -3,8 +3,8 @@ Date: January 2008 | |||
3 | Contact: Peter Zijlstra <a.p.zijlstra@chello.nl> | 3 | Contact: Peter Zijlstra <a.p.zijlstra@chello.nl> |
4 | Description: | 4 | Description: |
5 | 5 | ||
6 | Provide a place in sysfs for the backing_dev_info object. | 6 | Provide a place in sysfs for the backing_dev_info object. This allows |
7 | This allows us to see and set the various BDI specific variables. | 7 | setting and retrieving various BDI specific variables. |
8 | 8 | ||
9 | The <bdi> identifier can be either of the following: | 9 | The <bdi> identifier can be either of the following: |
10 | 10 | ||
@@ -26,34 +26,21 @@ read_ahead_kb (read-write) | |||
26 | 26 | ||
27 | Size of the read-ahead window in kilobytes | 27 | Size of the read-ahead window in kilobytes |
28 | 28 | ||
29 | reclaimable_kb (read-only) | ||
30 | |||
31 | Reclaimable (dirty or unstable) memory destined for writeback | ||
32 | to this device | ||
33 | |||
34 | writeback_kb (read-only) | ||
35 | |||
36 | Memory currently under writeback to this device | ||
37 | |||
38 | dirty_kb (read-only) | ||
39 | |||
40 | Global threshold for reclaimable + writeback memory | ||
41 | |||
42 | bdi_dirty_kb (read-only) | ||
43 | |||
44 | Current threshold on this BDI for reclaimable + writeback | ||
45 | memory | ||
46 | |||
47 | min_ratio (read-write) | 29 | min_ratio (read-write) |
48 | 30 | ||
49 | Minimal percentage of global dirty threshold allocated to this | 31 | Under normal circumstances each device is given a part of the |
50 | bdi. If the value written to this file would make the the sum | 32 | total write-back cache that relates to its current average |
51 | of all min_ratio values exceed 100, then EINVAL is returned. | 33 | writeout speed in relation to the other devices. |
52 | If min_ratio would become larger than the current max_ratio, | 34 | |
53 | then also EINVAL is returned. The default is zero | 35 | The 'min_ratio' parameter allows assigning a minimum |
36 | percentage of the write-back cache to a particular device. | ||
37 | For example, this is useful for providing a minimum QoS. | ||
54 | 38 | ||
55 | max_ratio (read-write) | 39 | max_ratio (read-write) |
56 | 40 | ||
57 | Maximal percentage of global dirty threshold allocated to this | 41 | Allows limiting a particular device to use not more than the |
58 | bdi. If max_ratio would become smaller than the current | 42 | given percentage of the write-back cache. This is useful in |
59 | min_ratio, then EINVAL is returned. The default is 100 | 43 | situations where we want to avoid one device taking all or |
44 | most of the write-back cache. For example in case of an NFS | ||
45 | mount that is prone to get stuck, or a FUSE mount which cannot | ||
46 | be trusted to play fair. | ||
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index ad3271d1e90a..c49a2d045e11 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | struct page; | 17 | struct page; |
18 | struct device; | 18 | struct device; |
19 | struct dentry; | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * Bits in backing_dev_info.state | 22 | * Bits in backing_dev_info.state |
@@ -55,6 +56,11 @@ struct backing_dev_info { | |||
55 | unsigned int max_ratio, max_prop_frac; | 56 | unsigned int max_ratio, max_prop_frac; |
56 | 57 | ||
57 | struct device *dev; | 58 | struct device *dev; |
59 | |||
60 | #ifdef CONFIG_DEBUG_FS | ||
61 | struct dentry *debug_dir; | ||
62 | struct dentry *debug_stats; | ||
63 | #endif | ||
58 | }; | 64 | }; |
59 | 65 | ||
60 | int bdi_init(struct backing_dev_info *bdi); | 66 | int bdi_init(struct backing_dev_info *bdi); |
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 08361b6aad50..7c4f9e097095 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -10,6 +10,80 @@ | |||
10 | 10 | ||
11 | static struct class *bdi_class; | 11 | static struct class *bdi_class; |
12 | 12 | ||
13 | #ifdef CONFIG_DEBUG_FS | ||
14 | #include <linux/debugfs.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | |||
17 | static struct dentry *bdi_debug_root; | ||
18 | |||
19 | static void bdi_debug_init(void) | ||
20 | { | ||
21 | bdi_debug_root = debugfs_create_dir("bdi", NULL); | ||
22 | } | ||
23 | |||
24 | static int bdi_debug_stats_show(struct seq_file *m, void *v) | ||
25 | { | ||
26 | struct backing_dev_info *bdi = m->private; | ||
27 | long background_thresh; | ||
28 | long dirty_thresh; | ||
29 | long bdi_thresh; | ||
30 | |||
31 | get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi); | ||
32 | |||
33 | #define K(x) ((x) << (PAGE_SHIFT - 10)) | ||
34 | seq_printf(m, | ||
35 | "BdiWriteback: %8lu kB\n" | ||
36 | "BdiReclaimable: %8lu kB\n" | ||
37 | "BdiDirtyThresh: %8lu kB\n" | ||
38 | "DirtyThresh: %8lu kB\n" | ||
39 | "BackgroundThresh: %8lu kB\n", | ||
40 | (unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)), | ||
41 | (unsigned long) K(bdi_stat(bdi, BDI_RECLAIMABLE)), | ||
42 | K(bdi_thresh), | ||
43 | K(dirty_thresh), | ||
44 | K(background_thresh)); | ||
45 | #undef K | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int bdi_debug_stats_open(struct inode *inode, struct file *file) | ||
51 | { | ||
52 | return single_open(file, bdi_debug_stats_show, inode->i_private); | ||
53 | } | ||
54 | |||
55 | static const struct file_operations bdi_debug_stats_fops = { | ||
56 | .open = bdi_debug_stats_open, | ||
57 | .read = seq_read, | ||
58 | .llseek = seq_lseek, | ||
59 | .release = single_release, | ||
60 | }; | ||
61 | |||
62 | static void bdi_debug_register(struct backing_dev_info *bdi, const char *name) | ||
63 | { | ||
64 | bdi->debug_dir = debugfs_create_dir(name, bdi_debug_root); | ||
65 | bdi->debug_stats = debugfs_create_file("stats", 0444, bdi->debug_dir, | ||
66 | bdi, &bdi_debug_stats_fops); | ||
67 | } | ||
68 | |||
69 | static void bdi_debug_unregister(struct backing_dev_info *bdi) | ||
70 | { | ||
71 | debugfs_remove(bdi->debug_stats); | ||
72 | debugfs_remove(bdi->debug_dir); | ||
73 | } | ||
74 | #else | ||
75 | static inline void bdi_debug_init(void) | ||
76 | { | ||
77 | } | ||
78 | static inline void bdi_debug_register(struct backing_dev_info *bdi, | ||
79 | const char *name) | ||
80 | { | ||
81 | } | ||
82 | static inline void bdi_debug_unregister(struct backing_dev_info *bdi) | ||
83 | { | ||
84 | } | ||
85 | #endif | ||
86 | |||
13 | static ssize_t read_ahead_kb_store(struct device *dev, | 87 | static ssize_t read_ahead_kb_store(struct device *dev, |
14 | struct device_attribute *attr, | 88 | struct device_attribute *attr, |
15 | const char *buf, size_t count) | 89 | const char *buf, size_t count) |
@@ -40,21 +114,6 @@ static ssize_t name##_show(struct device *dev, \ | |||
40 | 114 | ||
41 | BDI_SHOW(read_ahead_kb, K(bdi->ra_pages)) | 115 | BDI_SHOW(read_ahead_kb, K(bdi->ra_pages)) |
42 | 116 | ||
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 | static ssize_t min_ratio_store(struct device *dev, | 117 | static ssize_t min_ratio_store(struct device *dev, |
59 | struct device_attribute *attr, const char *buf, size_t count) | 118 | struct device_attribute *attr, const char *buf, size_t count) |
60 | { | 119 | { |
@@ -95,10 +154,6 @@ BDI_SHOW(max_ratio, bdi->max_ratio) | |||
95 | 154 | ||
96 | static struct device_attribute bdi_dev_attrs[] = { | 155 | static struct device_attribute bdi_dev_attrs[] = { |
97 | __ATTR_RW(read_ahead_kb), | 156 | __ATTR_RW(read_ahead_kb), |
98 | __ATTR_RO(reclaimable_kb), | ||
99 | __ATTR_RO(writeback_kb), | ||
100 | __ATTR_RO(dirty_kb), | ||
101 | __ATTR_RO(bdi_dirty_kb), | ||
102 | __ATTR_RW(min_ratio), | 157 | __ATTR_RW(min_ratio), |
103 | __ATTR_RW(max_ratio), | 158 | __ATTR_RW(max_ratio), |
104 | __ATTR_NULL, | 159 | __ATTR_NULL, |
@@ -108,10 +163,11 @@ static __init int bdi_class_init(void) | |||
108 | { | 163 | { |
109 | bdi_class = class_create(THIS_MODULE, "bdi"); | 164 | bdi_class = class_create(THIS_MODULE, "bdi"); |
110 | bdi_class->dev_attrs = bdi_dev_attrs; | 165 | bdi_class->dev_attrs = bdi_dev_attrs; |
166 | bdi_debug_init(); | ||
111 | return 0; | 167 | return 0; |
112 | } | 168 | } |
113 | 169 | ||
114 | core_initcall(bdi_class_init); | 170 | postcore_initcall(bdi_class_init); |
115 | 171 | ||
116 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, | 172 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, |
117 | const char *fmt, ...) | 173 | const char *fmt, ...) |
@@ -136,6 +192,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, | |||
136 | 192 | ||
137 | bdi->dev = dev; | 193 | bdi->dev = dev; |
138 | dev_set_drvdata(bdi->dev, bdi); | 194 | dev_set_drvdata(bdi->dev, bdi); |
195 | bdi_debug_register(bdi, name); | ||
139 | 196 | ||
140 | exit: | 197 | exit: |
141 | kfree(name); | 198 | kfree(name); |
@@ -152,6 +209,7 @@ EXPORT_SYMBOL(bdi_register_dev); | |||
152 | void bdi_unregister(struct backing_dev_info *bdi) | 209 | void bdi_unregister(struct backing_dev_info *bdi) |
153 | { | 210 | { |
154 | if (bdi->dev) { | 211 | if (bdi->dev) { |
212 | bdi_debug_unregister(bdi); | ||
155 | device_unregister(bdi->dev); | 213 | device_unregister(bdi->dev); |
156 | bdi->dev = NULL; | 214 | bdi->dev = NULL; |
157 | } | 215 | } |