path: root/mm/backing-dev.c
diff options
authorPeter Zijlstra <>2007-10-16 23:25:50 -0700
committerLinus Torvalds <>2007-10-17 08:42:45 -0700
commit04fbfdc14e5f48463820d6b9807daa5e9c92c51f (patch)
treec62905212c8c6373b2258c7f528398d3c831b075 /mm/backing-dev.c
parent145ca25eb2fbd20d4faf1bad4628c7650332058f (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. [ fix warnings] [ Fix occasional hang when a task couldn't get out of balance_dirty_pages] Signed-off-by: Peter Zijlstra <> Signed-off-by: Hugh Dickins <> Signed-off-by: Andrew Morton <> Signed-off-by: Linus Torvalds <>
Diffstat (limited to 'mm/backing-dev.c')
1 files changed, 14 insertions, 5 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index a47065e084a..b0ceb29da4c 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -12,11 +12,17 @@ int bdi_init(struct backing_dev_info *bdi)
for (i = 0; i < NR_BDI_STAT_ITEMS; i++) {
err = percpu_counter_init_irq(&bdi->bdi_stat[i], 0);
- if (err) {
- for (j = 0; j < i; j++)
- percpu_counter_destroy(&bdi->bdi_stat[i]);
- break;
- }
+ if (err)
+ goto err;
+ }
+ bdi->dirty_exceeded = 0;
+ err = prop_local_init_percpu(&bdi->completions);
+ if (err) {
+ for (j = 0; j < i; j++)
+ percpu_counter_destroy(&bdi->bdi_stat[i]);
return err;
@@ -29,6 +35,8 @@ void bdi_destroy(struct backing_dev_info *bdi)
for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
+ prop_local_destroy_percpu(&bdi->completions);
@@ -81,3 +89,4 @@ long congestion_wait(int rw, long timeout)
return ret;