aboutsummaryrefslogtreecommitdiffstats
path: root/mm/vmscan.c
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2012-11-29 16:54:23 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-11-30 11:51:17 -0500
commit60cefed485a02bd99b6299dad70666fe49245da7 (patch)
tree4392ca5fa1cb409d3badc786bf5e2d0fed34ab1c /mm/vmscan.c
parentae64ffcac35de0db628ba9631edf8ff34c5cd7ac (diff)
mm: vmscan: fix endless loop in kswapd balancing
Kswapd does not in all places have the same criteria for a balanced zone. Zones are only being reclaimed when their high watermark is breached, but compaction checks loop over the zonelist again when the zone does not meet the low watermark plus two times the size of the allocation. This gets kswapd stuck in an endless loop over a small zone, like the DMA zone, where the high watermark is smaller than the compaction requirement. Add a function, zone_balanced(), that checks the watermark, and, for higher order allocations, if compaction has enough free memory. Then use it uniformly to check for balanced zones. This makes sure that when the compaction watermark is not met, at least reclaim happens and progress is made - or the zone is declared unreclaimable at some point and skipped entirely. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Reported-by: George Spelvin <linux@horizon.com> Reported-by: Johannes Hirte <johannes.hirte@fem.tu-ilmenau.de> Reported-by: Tomas Racek <tracek@redhat.com> Tested-by: Johannes Hirte <johannes.hirte@fem.tu-ilmenau.de> Reviewed-by: Rik van Riel <riel@redhat.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: <stable@vger.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.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c
index cbf84e152f04..83f4d0e85601 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2414,6 +2414,19 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
2414 } while (memcg); 2414 } while (memcg);
2415} 2415}
2416 2416
2417static bool zone_balanced(struct zone *zone, int order,
2418 unsigned long balance_gap, int classzone_idx)
2419{
2420 if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone) +
2421 balance_gap, classzone_idx, 0))
2422 return false;
2423
2424 if (COMPACTION_BUILD && order && !compaction_suitable(zone, order))
2425 return false;
2426
2427 return true;
2428}
2429
2417/* 2430/*
2418 * pgdat_balanced is used when checking if a node is balanced for high-order 2431 * pgdat_balanced is used when checking if a node is balanced for high-order
2419 * allocations. Only zones that meet watermarks and are in a zone allowed 2432 * allocations. Only zones that meet watermarks and are in a zone allowed
@@ -2492,8 +2505,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
2492 continue; 2505 continue;
2493 } 2506 }
2494 2507
2495 if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), 2508 if (!zone_balanced(zone, order, 0, i))
2496 i, 0))
2497 all_zones_ok = false; 2509 all_zones_ok = false;
2498 else 2510 else
2499 balanced += zone->present_pages; 2511 balanced += zone->present_pages;
@@ -2602,8 +2614,7 @@ loop_again:
2602 break; 2614 break;
2603 } 2615 }
2604 2616
2605 if (!zone_watermark_ok_safe(zone, order, 2617 if (!zone_balanced(zone, order, 0, 0)) {
2606 high_wmark_pages(zone), 0, 0)) {
2607 end_zone = i; 2618 end_zone = i;
2608 break; 2619 break;
2609 } else { 2620 } else {
@@ -2679,9 +2690,8 @@ loop_again:
2679 testorder = 0; 2690 testorder = 0;
2680 2691
2681 if ((buffer_heads_over_limit && is_highmem_idx(i)) || 2692 if ((buffer_heads_over_limit && is_highmem_idx(i)) ||
2682 !zone_watermark_ok_safe(zone, testorder, 2693 !zone_balanced(zone, testorder,
2683 high_wmark_pages(zone) + balance_gap, 2694 balance_gap, end_zone)) {
2684 end_zone, 0)) {
2685 shrink_zone(zone, &sc); 2695 shrink_zone(zone, &sc);
2686 2696
2687 reclaim_state->reclaimed_slab = 0; 2697 reclaim_state->reclaimed_slab = 0;
@@ -2708,8 +2718,7 @@ loop_again:
2708 continue; 2718 continue;
2709 } 2719 }
2710 2720
2711 if (!zone_watermark_ok_safe(zone, testorder, 2721 if (!zone_balanced(zone, testorder, 0, end_zone)) {
2712 high_wmark_pages(zone), end_zone, 0)) {
2713 all_zones_ok = 0; 2722 all_zones_ok = 0;
2714 /* 2723 /*
2715 * We are still under min water mark. This 2724 * We are still under min water mark. This