aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorMel Gorman <mel@csn.ul.ie>2009-06-16 18:33:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:47:45 -0400
commitfa5e084e43eb14c14942027e1e2e894aeed96097 (patch)
tree3e7ebf714858e8dd1de7042fd1ef62294a3ec20f /mm/page_alloc.c
parent90afa5de6f3fa89a733861e843377302479fcf7e (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.c26
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
1491try_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)