aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fs-writeback.c2
-rw-r--r--include/linux/writeback.h5
-rw-r--r--mm/backing-dev.c3
-rw-r--r--mm/page-writeback.c75
4 files changed, 44 insertions, 41 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 2f76c4a081a2..fca43d4d7bf4 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -590,7 +590,7 @@ static inline bool over_bground_thresh(void)
590{ 590{
591 unsigned long background_thresh, dirty_thresh; 591 unsigned long background_thresh, dirty_thresh;
592 592
593 get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); 593 global_dirty_limits(&background_thresh, &dirty_thresh);
594 594
595 return (global_page_state(NR_FILE_DIRTY) + 595 return (global_page_state(NR_FILE_DIRTY) +
596 global_page_state(NR_UNSTABLE_NFS) >= background_thresh); 596 global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index c24eca71e80c..72a5d647a5f2 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -124,8 +124,9 @@ struct ctl_table;
124int dirty_writeback_centisecs_handler(struct ctl_table *, int, 124int dirty_writeback_centisecs_handler(struct ctl_table *, int,
125 void __user *, size_t *, loff_t *); 125 void __user *, size_t *, loff_t *);
126 126
127void get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty, 127void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
128 unsigned long *pbdi_dirty, struct backing_dev_info *bdi); 128unsigned long bdi_dirty_limit(struct backing_dev_info *bdi,
129 unsigned long dirty);
129 130
130void page_writeback_init(void); 131void page_writeback_init(void);
131void balance_dirty_pages_ratelimited_nr(struct address_space *mapping, 132void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 08d357522e78..eaa4a5bbe063 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -81,7 +81,8 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
81 nr_more_io++; 81 nr_more_io++;
82 spin_unlock(&inode_lock); 82 spin_unlock(&inode_lock);
83 83
84 get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi); 84 global_dirty_limits(&background_thresh, &dirty_thresh);
85 bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
85 86
86#define K(x) ((x) << (PAGE_SHIFT - 10)) 87#define K(x) ((x) << (PAGE_SHIFT - 10))
87 seq_printf(m, 88 seq_printf(m,
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 2cf69a5e46e6..1ea13ef350a8 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -267,10 +267,11 @@ static inline void task_dirties_fraction(struct task_struct *tsk,
267 * 267 *
268 * dirty -= (dirty/8) * p_{t} 268 * dirty -= (dirty/8) * p_{t}
269 */ 269 */
270static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty) 270static unsigned long task_dirty_limit(struct task_struct *tsk,
271 unsigned long bdi_dirty)
271{ 272{
272 long numerator, denominator; 273 long numerator, denominator;
273 unsigned long dirty = *pdirty; 274 unsigned long dirty = bdi_dirty;
274 u64 inv = dirty >> 3; 275 u64 inv = dirty >> 3;
275 276
276 task_dirties_fraction(tsk, &numerator, &denominator); 277 task_dirties_fraction(tsk, &numerator, &denominator);
@@ -278,10 +279,8 @@ static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty)
278 do_div(inv, denominator); 279 do_div(inv, denominator);
279 280
280 dirty -= inv; 281 dirty -= inv;
281 if (dirty < *pdirty/2)
282 dirty = *pdirty/2;
283 282
284 *pdirty = dirty; 283 return max(dirty, bdi_dirty/2);
285} 284}
286 285
287/* 286/*
@@ -391,9 +390,7 @@ unsigned long determine_dirtyable_memory(void)
391 return x + 1; /* Ensure that we never return 0 */ 390 return x + 1; /* Ensure that we never return 0 */
392} 391}
393 392
394void 393void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
395get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty,
396 unsigned long *pbdi_dirty, struct backing_dev_info *bdi)
397{ 394{
398 unsigned long background; 395 unsigned long background;
399 unsigned long dirty; 396 unsigned long dirty;
@@ -425,26 +422,28 @@ get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty,
425 } 422 }
426 *pbackground = background; 423 *pbackground = background;
427 *pdirty = dirty; 424 *pdirty = dirty;
425}
428 426
429 if (bdi) { 427unsigned long bdi_dirty_limit(struct backing_dev_info *bdi,
430 u64 bdi_dirty; 428 unsigned long dirty)
431 long numerator, denominator; 429{
430 u64 bdi_dirty;
431 long numerator, denominator;
432 432
433 /* 433 /*
434 * Calculate this BDI's share of the dirty ratio. 434 * Calculate this BDI's share of the dirty ratio.
435 */ 435 */
436 bdi_writeout_fraction(bdi, &numerator, &denominator); 436 bdi_writeout_fraction(bdi, &numerator, &denominator);
437 437
438 bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100; 438 bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100;
439 bdi_dirty *= numerator; 439 bdi_dirty *= numerator;
440 do_div(bdi_dirty, denominator); 440 do_div(bdi_dirty, denominator);
441 bdi_dirty += (dirty * bdi->min_ratio) / 100;
442 if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
443 bdi_dirty = dirty * bdi->max_ratio / 100;
444 441
445 *pbdi_dirty = bdi_dirty; 442 bdi_dirty += (dirty * bdi->min_ratio) / 100;
446 task_dirty_limit(current, pbdi_dirty); 443 if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
447 } 444 bdi_dirty = dirty * bdi->max_ratio / 100;
445
446 return bdi_dirty;
448} 447}
449 448
450/* 449/*
@@ -475,13 +474,24 @@ static void balance_dirty_pages(struct address_space *mapping,
475 .range_cyclic = 1, 474 .range_cyclic = 1,
476 }; 475 };
477 476
478 get_dirty_limits(&background_thresh, &dirty_thresh,
479 &bdi_thresh, bdi);
480
481 nr_reclaimable = global_page_state(NR_FILE_DIRTY) + 477 nr_reclaimable = global_page_state(NR_FILE_DIRTY) +
482 global_page_state(NR_UNSTABLE_NFS); 478 global_page_state(NR_UNSTABLE_NFS);
483 nr_writeback = global_page_state(NR_WRITEBACK); 479 nr_writeback = global_page_state(NR_WRITEBACK);
484 480
481 global_dirty_limits(&background_thresh, &dirty_thresh);
482
483 /*
484 * Throttle it only when the background writeback cannot
485 * catch-up. This avoids (excessively) small writeouts
486 * when the bdi limits are ramping up.
487 */
488 if (nr_reclaimable + nr_writeback <
489 (background_thresh + dirty_thresh) / 2)
490 break;
491
492 bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
493 bdi_thresh = task_dirty_limit(current, bdi_thresh);
494
485 /* 495 /*
486 * In order to avoid the stacked BDI deadlock we need 496 * In order to avoid the stacked BDI deadlock we need
487 * to ensure we accurately count the 'dirty' pages when 497 * to ensure we accurately count the 'dirty' pages when
@@ -513,15 +523,6 @@ static void balance_dirty_pages(struct address_space *mapping,
513 if (!dirty_exceeded) 523 if (!dirty_exceeded)
514 break; 524 break;
515 525
516 /*
517 * Throttle it only when the background writeback cannot
518 * catch-up. This avoids (excessively) small writeouts
519 * when the bdi limits are ramping up.
520 */
521 if (nr_reclaimable + nr_writeback <
522 (background_thresh + dirty_thresh) / 2)
523 break;
524
525 if (!bdi->dirty_exceeded) 526 if (!bdi->dirty_exceeded)
526 bdi->dirty_exceeded = 1; 527 bdi->dirty_exceeded = 1;
527 528
@@ -634,7 +635,7 @@ void throttle_vm_writeout(gfp_t gfp_mask)
634 unsigned long dirty_thresh; 635 unsigned long dirty_thresh;
635 636
636 for ( ; ; ) { 637 for ( ; ; ) {
637 get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); 638 global_dirty_limits(&background_thresh, &dirty_thresh);
638 639
639 /* 640 /*
640 * Boost the allowable dirty threshold a bit for page 641 * Boost the allowable dirty threshold a bit for page