diff options
author | Mel Gorman <mel@csn.ul.ie> | 2009-06-16 18:33:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:45 -0400 |
commit | fa5e084e43eb14c14942027e1e2e894aeed96097 (patch) | |
tree | 3e7ebf714858e8dd1de7042fd1ef62294a3ec20f /mm/page_alloc.c | |
parent | 90afa5de6f3fa89a733861e843377302479fcf7e (diff) |
vmscan: do not unconditionally treat zones that fail zone_reclaim() as full
On NUMA machines, the administrator can configure zone_reclaim_mode that
is a more targetted form of direct reclaim. On machines with large NUMA
distances for example, a zone_reclaim_mode defaults to 1 meaning that
clean unmapped pages will be reclaimed if the zone watermarks are not
being met. The problem is that zone_reclaim() failing at all means the
zone gets marked full.
This can cause situations where a zone is usable, but is being skipped
because it has been considered full. Take a situation where a large tmpfs
mount is occuping a large percentage of memory overall. The pages do not
get cleaned or reclaimed by zone_reclaim(), but the zone gets marked full
and the zonelist cache considers them not worth trying in the future.
This patch makes zone_reclaim() return more fine-grained information about
what occured when zone_reclaim() failued. The zone only gets marked full
if it really is unreclaimable. If it's a case that the scan did not occur
or if enough pages were not reclaimed with the limited reclaim_mode, then
the zone is simply skipped.
There is a side-effect to this patch. Currently, if zone_reclaim()
successfully reclaimed SWAP_CLUSTER_MAX, an allocation attempt would go
ahead. With this patch applied, zone watermarks are rechecked after
zone_reclaim() does some work.
This bug was introduced by commit 9276b1bc96a132f4068fdee00983c532f43d3a26
("memory page_alloc zonelist caching speedup") way back in 2.6.19 when the
zonelist_cache was introduced. It was not intended that zone_reclaim()
aggressively consider the zone to be full when it failed as full direct
reclaim can still be an option. Due to the age of the bug, it should be
considered a -stable candidate.
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Reviewed-by: Wu Fengguang <fengguang.wu@intel.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6407cbfccd77..2f457a756d46 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1462,15 +1462,33 @@ zonelist_scan: | |||
1462 | BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK); | 1462 | BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK); |
1463 | if (!(alloc_flags & ALLOC_NO_WATERMARKS)) { | 1463 | if (!(alloc_flags & ALLOC_NO_WATERMARKS)) { |
1464 | unsigned long mark; | 1464 | unsigned long mark; |
1465 | int ret; | ||
1466 | |||
1465 | mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK]; | 1467 | mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK]; |
1466 | if (!zone_watermark_ok(zone, order, mark, | 1468 | if (zone_watermark_ok(zone, order, mark, |
1467 | classzone_idx, alloc_flags)) { | 1469 | classzone_idx, alloc_flags)) |
1468 | if (!zone_reclaim_mode || | 1470 | goto try_this_zone; |
1469 | !zone_reclaim(zone, gfp_mask, order)) | 1471 | |
1472 | if (zone_reclaim_mode == 0) | ||
1473 | goto this_zone_full; | ||
1474 | |||
1475 | ret = zone_reclaim(zone, gfp_mask, order); | ||
1476 | switch (ret) { | ||
1477 | case ZONE_RECLAIM_NOSCAN: | ||
1478 | /* did not scan */ | ||
1479 | goto try_next_zone; | ||
1480 | case ZONE_RECLAIM_FULL: | ||
1481 | /* scanned but unreclaimable */ | ||
1482 | goto this_zone_full; | ||
1483 | default: | ||
1484 | /* did we reclaim enough */ | ||
1485 | if (!zone_watermark_ok(zone, order, mark, | ||
1486 | classzone_idx, alloc_flags)) | ||
1470 | goto this_zone_full; | 1487 | goto this_zone_full; |
1471 | } | 1488 | } |
1472 | } | 1489 | } |
1473 | 1490 | ||
1491 | try_this_zone: | ||
1474 | page = buffered_rmqueue(preferred_zone, zone, order, | 1492 | page = buffered_rmqueue(preferred_zone, zone, order, |
1475 | gfp_mask, migratetype); | 1493 | gfp_mask, migratetype); |
1476 | if (page) | 1494 | if (page) |