summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2011-11-13 19:47:32 -0600
committerWu Fengguang <fengguang.wu@intel.com>2011-11-17 20:39:32 +0800
commit1df647197c5b8aacaeb58592cba9a1df322c9000 (patch)
treed413b165aca10d3a6058e39430680e38c09c0037 /include
parent499d05ecf990a7a7bbf9e0a273f9969f8ec69efc (diff)
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: Wu Fengguang <fengguang.wu@intel.com>
Diffstat (limited to 'include')
0 files changed, 0 insertions, 0 deletions