diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2007-10-17 02:25:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:45 -0400 |
commit | 04fbfdc14e5f48463820d6b9807daa5e9c92c51f (patch) | |
tree | c62905212c8c6373b2258c7f528398d3c831b075 /include | |
parent | 145ca25eb2fbd20d4faf1bad4628c7650332058f (diff) |
mm: per device dirty threshold
Scale writeback cache per backing device, proportional to its writeout speed.
By decoupling the BDI dirty thresholds a number of problems we currently have
will go away, namely:
- mutual interference starvation (for any number of BDIs);
- deadlocks with stacked BDIs (loop, FUSE and local NFS mounts).
It might be that all dirty pages are for a single BDI while other BDIs are
idling. By giving each BDI a 'fair' share of the dirty limit, each one can have
dirty pages outstanding and make progress.
A global threshold also creates a deadlock for stacked BDIs; when A writes to
B, and A generates enough dirty pages to get throttled, B will never start
writeback until the dirty pages go away. Again, by giving each BDI its own
'independent' dirty limit, this problem is avoided.
So the problem is to determine how to distribute the total dirty limit across
the BDIs fairly and efficiently. A DBI that has a large dirty limit but does
not have any dirty pages outstanding is a waste.
What is done is to keep a floating proportion between the DBIs based on
writeback completions. This way faster/more active devices get a larger share
than slower/idle devices.
[akpm@linux-foundation.org: fix warnings]
[hugh@veritas.com: Fix occasional hang when a task couldn't get out of balance_dirty_pages]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/backing-dev.h | 4 | ||||
-rw-r--r-- | include/linux/writeback.h | 4 |
2 files changed, 8 insertions, 0 deletions
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 4d9222c2f222..48a62baace58 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/percpu_counter.h> | 11 | #include <linux/percpu_counter.h> |
12 | #include <linux/log2.h> | 12 | #include <linux/log2.h> |
13 | #include <linux/proportions.h> | ||
13 | #include <asm/atomic.h> | 14 | #include <asm/atomic.h> |
14 | 15 | ||
15 | struct page; | 16 | struct page; |
@@ -44,6 +45,9 @@ struct backing_dev_info { | |||
44 | void *unplug_io_data; | 45 | void *unplug_io_data; |
45 | 46 | ||
46 | struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS]; | 47 | struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS]; |
48 | |||
49 | struct prop_local_percpu completions; | ||
50 | int dirty_exceeded; | ||
47 | }; | 51 | }; |
48 | 52 | ||
49 | int bdi_init(struct backing_dev_info *bdi); | 53 | int bdi_init(struct backing_dev_info *bdi); |
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index d1321a81c9c4..52be879793ed 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -97,6 +97,10 @@ extern int dirty_expire_interval; | |||
97 | extern int block_dump; | 97 | extern int block_dump; |
98 | extern int laptop_mode; | 98 | extern int laptop_mode; |
99 | 99 | ||
100 | extern int dirty_ratio_handler(struct ctl_table *table, int write, | ||
101 | struct file *filp, void __user *buffer, size_t *lenp, | ||
102 | loff_t *ppos); | ||
103 | |||
100 | struct ctl_table; | 104 | struct ctl_table; |
101 | struct file; | 105 | struct file; |
102 | int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *, | 106 | int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *, |