Maintain a smoothed version of dirty pages for use in the throttle bandwidth calculations. default_backing_dev_info.avg_dirty holds the smoothed global dirty pages. Signed-off-by: Wu Fengguang <fengguang.wu@xxxxxxxxx> --- include/linux/backing-dev.h | 2 + mm/backing-dev.c | 3 + mm/page-writeback.c | 62 ++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) --- linux-next.orig/mm/page-writeback.c 2011-03-03 14:44:07.000000000 +0800 +++ linux-next/mm/page-writeback.c 2011-03-03 14:44:10.000000000 +0800 @@ -472,6 +472,64 @@ unsigned long bdi_dirty_limit(struct bac return bdi_dirty; } +static void bdi_update_dirty_smooth(struct backing_dev_info *bdi, + unsigned long dirty) +{ + unsigned long avg = bdi->avg_dirty; + unsigned long old = bdi->old_dirty; + + if (unlikely(!avg)) { + avg = dirty; + goto update; + } + + /* + * dirty pages are departing upwards, follow up + */ + if (avg < old && old <= dirty) { + avg += (old - avg) >> 3; + goto update; + } + + /* + * dirty pages are departing downwards, follow down + */ + if (avg > old && old >= dirty) { + avg -= (avg - old) >> 3; + goto update; + } + + /* + * This can filter out one half unnecessary updates when bdi_dirty is + * fluctuating around the balance point, and is most effective on XFS, + * whose pattern is + * . + * [.] dirty [-] avg . . + * . . + * . . . . . . + * --------------------------------------- . . + * . . . . . . + * . . . . . . + * . . . . . . + * . . . . . . + * . . . . + * . . . . (flucuated) + * . . . . + * . . . . + * + * @avg will remain flat at the cost of being biased towards high. In + * practice the error tend to be much smaller: thanks to more coarse + * grained fluctuations, @avg becomes the real average number for the + * last two rising lines of @dirty. + */ + goto out; + +update: + bdi->avg_dirty = avg; +out: + bdi->old_dirty = dirty; +} + static void __bdi_update_write_bandwidth(struct backing_dev_info *bdi, unsigned long elapsed, unsigned long written) @@ -537,6 +595,10 @@ void bdi_update_bandwidth(struct backing goto unlock; __bdi_update_write_bandwidth(bdi, elapsed, written); + if (thresh) { + bdi_update_dirty_smooth(bdi, bdi_dirty); + bdi_update_dirty_smooth(&default_backing_dev_info, dirty); + } snapshot: bdi->written_stamp = written; --- linux-next.orig/include/linux/backing-dev.h 2011-03-03 14:44:07.000000000 +0800 +++ linux-next/include/linux/backing-dev.h 2011-03-03 14:44:10.000000000 +0800 @@ -79,6 +79,8 @@ struct backing_dev_info { unsigned long written_stamp; unsigned long write_bandwidth; unsigned long avg_bandwidth; + unsigned long avg_dirty; + unsigned long old_dirty; struct prop_local_percpu completions; int dirty_exceeded; --- linux-next.orig/mm/backing-dev.c 2011-03-03 14:44:07.000000000 +0800 +++ linux-next/mm/backing-dev.c 2011-03-03 14:44:10.000000000 +0800 @@ -675,6 +675,9 @@ int bdi_init(struct backing_dev_info *bd bdi->write_bandwidth = INIT_BW; bdi->avg_bandwidth = INIT_BW; + bdi->avg_dirty = 0; + bdi->old_dirty = 0; + err = prop_local_init_percpu(&bdi->completions); if (err) { -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxxx For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>