aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page-writeback.c
diff options
context:
space:
mode:
authorJohannes Weiner <jweiner@redhat.com>2012-01-10 18:07:49 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-10 19:30:43 -0500
commita756cf5908530e8b40bdf569eb48b40139e8d7fd (patch)
treeba9df151d5468098c7eae563ce09faea6a539fc0 /mm/page-writeback.c
parentccafa2879fb8d13b8031337a8743eac4189e5d6e (diff)
mm: try to distribute dirty pages fairly across zones
The maximum number of dirty pages that exist in the system at any time is determined by a number of pages considered dirtyable and a user-configured percentage of those, or an absolute number in bytes. This number of dirtyable pages is the sum of memory provided by all the zones in the system minus their lowmem reserves and high watermarks, so that the system can retain a healthy number of free pages without having to reclaim dirty pages. But there is a flaw in that we have a zoned page allocator which does not care about the global state but rather the state of individual memory zones. And right now there is nothing that prevents one zone from filling up with dirty pages while other zones are spared, which frequently leads to situations where kswapd, in order to restore the watermark of free pages, does indeed have to write pages from that zone's LRU list. This can interfere so badly with IO from the flusher threads that major filesystems (btrfs, xfs, ext4) mostly ignore write requests from reclaim already, taking away the VM's only possibility to keep such a zone balanced, aside from hoping the flushers will soon clean pages from that zone. Enter per-zone dirty limits. They are to a zone's dirtyable memory what the global limit is to the global amount of dirtyable memory, and try to make sure that no single zone receives more than its fair share of the globally allowed dirty pages in the first place. As the number of pages considered dirtyable excludes the zones' lowmem reserves and high watermarks, the maximum number of dirty pages in a zone is such that the zone can always be balanced without requiring page cleaning. As this is a placement decision in the page allocator and pages are dirtied only after the allocation, this patch allows allocators to pass __GFP_WRITE when they know in advance that the page will be written to and become dirty soon. The page allocator will then attempt to allocate from the first zone of the zonelist - which on NUMA is determined by the task's NUMA memory policy - that has not exceeded its dirty limit. At first glance, it would appear that the diversion to lower zones can increase pressure on them, but this is not the case. With a full high zone, allocations will be diverted to lower zones eventually, so it is more of a shift in timing of the lower zone allocations. Workloads that previously could fit their dirty pages completely in the higher zone may be forced to allocate from lower zones, but the amount of pages that "spill over" are limited themselves by the lower zones' dirty constraints, and thus unlikely to become a problem. For now, the problem of unfair dirty page distribution remains for NUMA configurations where the zones allowed for allocation are in sum not big enough to trigger the global dirty limits, wake up the flusher threads and remedy the situation. Because of this, an allocation that could not succeed on any of the considered zones is allowed to ignore the dirty limits before going into direct reclaim or even failing the allocation, until a future patch changes the global dirty throttling and flusher thread activation so that they take individual zone states into account. Test results 15M DMA + 3246M DMA32 + 504 Normal = 3765M memory 40% dirty ratio 16G USB thumb drive 10 runs of dd if=/dev/zero of=disk/zeroes bs=32k count=$((10 << 15)) seconds nr_vmscan_write (stddev) min| median| max xfs vanilla: 549.747( 3.492) 0.000| 0.000| 0.000 patched: 550.996( 3.802) 0.000| 0.000| 0.000 fuse-ntfs vanilla: 1183.094(53.178) 54349.000| 59341.000| 65163.000 patched: 558.049(17.914) 0.000| 0.000| 43.000 btrfs vanilla: 573.679(14.015) 156657.000| 460178.000| 606926.000 patched: 563.365(11.368) 0.000| 0.000| 1362.000 ext4 vanilla: 561.197(15.782) 0.000|2725438.000|4143837.000 patched: 568.806(17.496) 0.000| 0.000| 0.000 Signed-off-by: Johannes Weiner <jweiner@redhat.com> Reviewed-by: Minchan Kim <minchan.kim@gmail.com> Acked-by: Mel Gorman <mgorman@suse.de> Reviewed-by: Michal Hocko <mhocko@suse.cz> Tested-by: Wu Fengguang <fengguang.wu@intel.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Dave Chinner <david@fromorbit.com> Cc: Jan Kara <jack@suse.cz> Cc: Shaohua Li <shaohua.li@intel.com> Cc: Rik van Riel <riel@redhat.com> Cc: Chris Mason <chris.mason@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page-writeback.c')
-rw-r--r--mm/page-writeback.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 433fa990fe8b..5cdd4f2b0c9d 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -147,6 +147,24 @@ static struct prop_descriptor vm_completions;
147 * clamping level. 147 * clamping level.
148 */ 148 */
149 149
150/*
151 * In a memory zone, there is a certain amount of pages we consider
152 * available for the page cache, which is essentially the number of
153 * free and reclaimable pages, minus some zone reserves to protect
154 * lowmem and the ability to uphold the zone's watermarks without
155 * requiring writeback.
156 *
157 * This number of dirtyable pages is the base value of which the
158 * user-configurable dirty ratio is the effictive number of pages that
159 * are allowed to be actually dirtied. Per individual zone, or
160 * globally by using the sum of dirtyable pages over all zones.
161 *
162 * Because the user is allowed to specify the dirty limit globally as
163 * absolute number of bytes, calculating the per-zone dirty limit can
164 * require translating the configured limit into a percentage of
165 * global dirtyable memory first.
166 */
167
150static unsigned long highmem_dirtyable_memory(unsigned long total) 168static unsigned long highmem_dirtyable_memory(unsigned long total)
151{ 169{
152#ifdef CONFIG_HIGHMEM 170#ifdef CONFIG_HIGHMEM
@@ -232,6 +250,70 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
232 trace_global_dirty_state(background, dirty); 250 trace_global_dirty_state(background, dirty);
233} 251}
234 252
253/**
254 * zone_dirtyable_memory - number of dirtyable pages in a zone
255 * @zone: the zone
256 *
257 * Returns the zone's number of pages potentially available for dirty
258 * page cache. This is the base value for the per-zone dirty limits.
259 */
260static unsigned long zone_dirtyable_memory(struct zone *zone)
261{
262 /*
263 * The effective global number of dirtyable pages may exclude
264 * highmem as a big-picture measure to keep the ratio between
265 * dirty memory and lowmem reasonable.
266 *
267 * But this function is purely about the individual zone and a
268 * highmem zone can hold its share of dirty pages, so we don't
269 * care about vm_highmem_is_dirtyable here.
270 */
271 return zone_page_state(zone, NR_FREE_PAGES) +
272 zone_reclaimable_pages(zone) -
273 zone->dirty_balance_reserve;
274}
275
276/**
277 * zone_dirty_limit - maximum number of dirty pages allowed in a zone
278 * @zone: the zone
279 *
280 * Returns the maximum number of dirty pages allowed in a zone, based
281 * on the zone's dirtyable memory.
282 */
283static unsigned long zone_dirty_limit(struct zone *zone)
284{
285 unsigned long zone_memory = zone_dirtyable_memory(zone);
286 struct task_struct *tsk = current;
287 unsigned long dirty;
288
289 if (vm_dirty_bytes)
290 dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE) *
291 zone_memory / global_dirtyable_memory();
292 else
293 dirty = vm_dirty_ratio * zone_memory / 100;
294
295 if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk))
296 dirty += dirty / 4;
297
298 return dirty;
299}
300
301/**
302 * zone_dirty_ok - tells whether a zone is within its dirty limits
303 * @zone: the zone to check
304 *
305 * Returns %true when the dirty pages in @zone are within the zone's
306 * dirty limit, %false if the limit is exceeded.
307 */
308bool zone_dirty_ok(struct zone *zone)
309{
310 unsigned long limit = zone_dirty_limit(zone);
311
312 return zone_page_state(zone, NR_FILE_DIRTY) +
313 zone_page_state(zone, NR_UNSTABLE_NFS) +
314 zone_page_state(zone, NR_WRITEBACK) <= limit;
315}
316
235/* 317/*
236 * couple the period to the dirty_ratio: 318 * couple the period to the dirty_ratio:
237 * 319 *