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/vmscan.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/vmscan.c')
-rw-r--r-- | mm/vmscan.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 79a98d98ed33..16c82a868e2b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -2492,16 +2492,16 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | |||
2492 | */ | 2492 | */ |
2493 | if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages && | 2493 | if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages && |
2494 | zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages) | 2494 | zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages) |
2495 | return 0; | 2495 | return ZONE_RECLAIM_FULL; |
2496 | 2496 | ||
2497 | if (zone_is_all_unreclaimable(zone)) | 2497 | if (zone_is_all_unreclaimable(zone)) |
2498 | return 0; | 2498 | return ZONE_RECLAIM_FULL; |
2499 | 2499 | ||
2500 | /* | 2500 | /* |
2501 | * Do not scan if the allocation should not be delayed. | 2501 | * Do not scan if the allocation should not be delayed. |
2502 | */ | 2502 | */ |
2503 | if (!(gfp_mask & __GFP_WAIT) || (current->flags & PF_MEMALLOC)) | 2503 | if (!(gfp_mask & __GFP_WAIT) || (current->flags & PF_MEMALLOC)) |
2504 | return 0; | 2504 | return ZONE_RECLAIM_NOSCAN; |
2505 | 2505 | ||
2506 | /* | 2506 | /* |
2507 | * Only run zone reclaim on the local zone or on zones that do not | 2507 | * Only run zone reclaim on the local zone or on zones that do not |
@@ -2511,10 +2511,11 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | |||
2511 | */ | 2511 | */ |
2512 | node_id = zone_to_nid(zone); | 2512 | node_id = zone_to_nid(zone); |
2513 | if (node_state(node_id, N_CPU) && node_id != numa_node_id()) | 2513 | if (node_state(node_id, N_CPU) && node_id != numa_node_id()) |
2514 | return 0; | 2514 | return ZONE_RECLAIM_NOSCAN; |
2515 | 2515 | ||
2516 | if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED)) | 2516 | if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED)) |
2517 | return 0; | 2517 | return ZONE_RECLAIM_NOSCAN; |
2518 | |||
2518 | ret = __zone_reclaim(zone, gfp_mask, order); | 2519 | ret = __zone_reclaim(zone, gfp_mask, order); |
2519 | zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); | 2520 | zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); |
2520 | 2521 | ||