diff options
-rw-r--r-- | fs/fs-writeback.c | 2 | ||||
-rw-r--r-- | include/linux/writeback.h | 5 | ||||
-rw-r--r-- | mm/backing-dev.c | 3 | ||||
-rw-r--r-- | mm/page-writeback.c | 75 |
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; | |||
124 | int dirty_writeback_centisecs_handler(struct ctl_table *, int, | 124 | int dirty_writeback_centisecs_handler(struct ctl_table *, int, |
125 | void __user *, size_t *, loff_t *); | 125 | void __user *, size_t *, loff_t *); |
126 | 126 | ||
127 | void get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty, | 127 | void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty); |
128 | unsigned long *pbdi_dirty, struct backing_dev_info *bdi); | 128 | unsigned long bdi_dirty_limit(struct backing_dev_info *bdi, |
129 | unsigned long dirty); | ||
129 | 130 | ||
130 | void page_writeback_init(void); | 131 | void page_writeback_init(void); |
131 | void balance_dirty_pages_ratelimited_nr(struct address_space *mapping, | 132 | void 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 | */ |
270 | static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty) | 270 | static 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 | ||
394 | void | 393 | void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty) |
395 | get_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) { | 427 | unsigned 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 |