Commit 1df64719 authored by Wu Fengguang's avatar Wu Fengguang

writeback: hard throttle 1000+ dd on a slow USB stick

The sleep based balance_dirty_pages() can pause at most MAX_PAUSE=200ms
on every 1 4KB-page, which means it cannot throttle a task under
4KB/200ms=20KB/s. So when there are more than 512 dd writing to a
10MB/s USB stick, its bdi dirty pages could grow out of control.

Even if we can increase MAX_PAUSE, the minimal (task_ratelimit = 1)
means a limit of 4KB/s.
                                                       
They can eventually be safeguarded by the global limit check 
(nr_dirty < dirty_thresh). However if someone is also writing to an 
HDD at the same time, it'll get poor HDD write performance.
                                                       
We at least want to maintain good write performance for other devices
when one device is attacked by some "massive parallel" workload, or
suffers from slow write bandwidth, or somehow get stalled due to some 
error condition (eg. NFS server not responding).

For a stalled device, we need to completely block its dirtiers, too,
before its bdi dirty pages grow all the way up to the global limit and
leave no space for the other functional devices.

So change the loop exit condition to

	/*
	 * Always enforce global dirty limit; also enforce bdi dirty limit
	 * if the normal max_pause sleeps cannot keep things under control.
	 */
	if (nr_dirty < dirty_thresh &&
	    (bdi_dirty < bdi_thresh || bdi->dirty_ratelimit > 1))
		break;

which can be further simplified to

	if (task_ratelimit)
		break;
Signed-off-by: default avatarWu Fengguang <fengguang.wu@intel.com>
parent 499d05ec
...@@ -1136,14 +1136,11 @@ static void balance_dirty_pages(struct address_space *mapping, ...@@ -1136,14 +1136,11 @@ static void balance_dirty_pages(struct address_space *mapping,
__set_current_state(TASK_KILLABLE); __set_current_state(TASK_KILLABLE);
io_schedule_timeout(pause); io_schedule_timeout(pause);
dirty_thresh = hard_dirty_limit(dirty_thresh);
/* /*
* max-pause area. If dirty exceeded but still within this * This is typically equal to (nr_dirty < dirty_thresh) and can
* area, no need to sleep for more than 200ms: (a) 8 pages per * also keep "1000+ dd on a slow USB stick" under control.
* 200ms is typically more than enough to curb heavy dirtiers;
* (b) the pause time limit makes the dirtiers more responsive.
*/ */
if (nr_dirty < dirty_thresh) if (task_ratelimit)
break; break;
if (fatal_signal_pending(current)) if (fatal_signal_pending(current))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment