diff options
Diffstat (limited to 'mm/vmscan.c')
-rw-r--r-- | mm/vmscan.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 4f49535d4cd3..d036e59d302b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -2310,7 +2310,8 @@ static bool pgdat_balanced(pg_data_t *pgdat, unsigned long balanced_pages, | |||
2310 | for (i = 0; i <= classzone_idx; i++) | 2310 | for (i = 0; i <= classzone_idx; i++) |
2311 | present_pages += pgdat->node_zones[i].present_pages; | 2311 | present_pages += pgdat->node_zones[i].present_pages; |
2312 | 2312 | ||
2313 | return balanced_pages > (present_pages >> 2); | 2313 | /* A special case here: if zone has no page, we think it's balanced */ |
2314 | return balanced_pages >= (present_pages >> 2); | ||
2314 | } | 2315 | } |
2315 | 2316 | ||
2316 | /* is kswapd sleeping prematurely? */ | 2317 | /* is kswapd sleeping prematurely? */ |
@@ -2326,7 +2327,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining, | |||
2326 | return true; | 2327 | return true; |
2327 | 2328 | ||
2328 | /* Check the watermark levels */ | 2329 | /* Check the watermark levels */ |
2329 | for (i = 0; i < pgdat->nr_zones; i++) { | 2330 | for (i = 0; i <= classzone_idx; i++) { |
2330 | struct zone *zone = pgdat->node_zones + i; | 2331 | struct zone *zone = pgdat->node_zones + i; |
2331 | 2332 | ||
2332 | if (!populated_zone(zone)) | 2333 | if (!populated_zone(zone)) |
@@ -2344,7 +2345,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining, | |||
2344 | } | 2345 | } |
2345 | 2346 | ||
2346 | if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), | 2347 | if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone), |
2347 | classzone_idx, 0)) | 2348 | i, 0)) |
2348 | all_zones_ok = false; | 2349 | all_zones_ok = false; |
2349 | else | 2350 | else |
2350 | balanced += zone->present_pages; | 2351 | balanced += zone->present_pages; |
@@ -2451,7 +2452,6 @@ loop_again: | |||
2451 | if (!zone_watermark_ok_safe(zone, order, | 2452 | if (!zone_watermark_ok_safe(zone, order, |
2452 | high_wmark_pages(zone), 0, 0)) { | 2453 | high_wmark_pages(zone), 0, 0)) { |
2453 | end_zone = i; | 2454 | end_zone = i; |
2454 | *classzone_idx = i; | ||
2455 | break; | 2455 | break; |
2456 | } | 2456 | } |
2457 | } | 2457 | } |
@@ -2510,18 +2510,18 @@ loop_again: | |||
2510 | KSWAPD_ZONE_BALANCE_GAP_RATIO); | 2510 | KSWAPD_ZONE_BALANCE_GAP_RATIO); |
2511 | if (!zone_watermark_ok_safe(zone, order, | 2511 | if (!zone_watermark_ok_safe(zone, order, |
2512 | high_wmark_pages(zone) + balance_gap, | 2512 | high_wmark_pages(zone) + balance_gap, |
2513 | end_zone, 0)) | 2513 | end_zone, 0)) { |
2514 | shrink_zone(priority, zone, &sc); | 2514 | shrink_zone(priority, zone, &sc); |
2515 | reclaim_state->reclaimed_slab = 0; | ||
2516 | nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages); | ||
2517 | sc.nr_reclaimed += reclaim_state->reclaimed_slab; | ||
2518 | total_scanned += sc.nr_scanned; | ||
2519 | 2515 | ||
2520 | if (zone->all_unreclaimable) | 2516 | reclaim_state->reclaimed_slab = 0; |
2521 | continue; | 2517 | nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages); |
2522 | if (nr_slab == 0 && | 2518 | sc.nr_reclaimed += reclaim_state->reclaimed_slab; |
2523 | !zone_reclaimable(zone)) | 2519 | total_scanned += sc.nr_scanned; |
2524 | zone->all_unreclaimable = 1; | 2520 | |
2521 | if (nr_slab == 0 && !zone_reclaimable(zone)) | ||
2522 | zone->all_unreclaimable = 1; | ||
2523 | } | ||
2524 | |||
2525 | /* | 2525 | /* |
2526 | * If we've done a decent amount of scanning and | 2526 | * If we've done a decent amount of scanning and |
2527 | * the reclaim ratio is low, start doing writepage | 2527 | * the reclaim ratio is low, start doing writepage |
@@ -2531,6 +2531,12 @@ loop_again: | |||
2531 | total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2) | 2531 | total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2) |
2532 | sc.may_writepage = 1; | 2532 | sc.may_writepage = 1; |
2533 | 2533 | ||
2534 | if (zone->all_unreclaimable) { | ||
2535 | if (end_zone && end_zone == i) | ||
2536 | end_zone--; | ||
2537 | continue; | ||
2538 | } | ||
2539 | |||
2534 | if (!zone_watermark_ok_safe(zone, order, | 2540 | if (!zone_watermark_ok_safe(zone, order, |
2535 | high_wmark_pages(zone), end_zone, 0)) { | 2541 | high_wmark_pages(zone), end_zone, 0)) { |
2536 | all_zones_ok = 0; | 2542 | all_zones_ok = 0; |
@@ -2709,8 +2715,8 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order, int classzone_idx) | |||
2709 | */ | 2715 | */ |
2710 | static int kswapd(void *p) | 2716 | static int kswapd(void *p) |
2711 | { | 2717 | { |
2712 | unsigned long order; | 2718 | unsigned long order, new_order; |
2713 | int classzone_idx; | 2719 | int classzone_idx, new_classzone_idx; |
2714 | pg_data_t *pgdat = (pg_data_t*)p; | 2720 | pg_data_t *pgdat = (pg_data_t*)p; |
2715 | struct task_struct *tsk = current; | 2721 | struct task_struct *tsk = current; |
2716 | 2722 | ||
@@ -2740,17 +2746,23 @@ static int kswapd(void *p) | |||
2740 | tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; | 2746 | tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; |
2741 | set_freezable(); | 2747 | set_freezable(); |
2742 | 2748 | ||
2743 | order = 0; | 2749 | order = new_order = 0; |
2744 | classzone_idx = MAX_NR_ZONES - 1; | 2750 | classzone_idx = new_classzone_idx = pgdat->nr_zones - 1; |
2745 | for ( ; ; ) { | 2751 | for ( ; ; ) { |
2746 | unsigned long new_order; | ||
2747 | int new_classzone_idx; | ||
2748 | int ret; | 2752 | int ret; |
2749 | 2753 | ||
2750 | new_order = pgdat->kswapd_max_order; | 2754 | /* |
2751 | new_classzone_idx = pgdat->classzone_idx; | 2755 | * If the last balance_pgdat was unsuccessful it's unlikely a |
2752 | pgdat->kswapd_max_order = 0; | 2756 | * new request of a similar or harder type will succeed soon |
2753 | pgdat->classzone_idx = MAX_NR_ZONES - 1; | 2757 | * so consider going to sleep on the basis we reclaimed at |
2758 | */ | ||
2759 | if (classzone_idx >= new_classzone_idx && order == new_order) { | ||
2760 | new_order = pgdat->kswapd_max_order; | ||
2761 | new_classzone_idx = pgdat->classzone_idx; | ||
2762 | pgdat->kswapd_max_order = 0; | ||
2763 | pgdat->classzone_idx = pgdat->nr_zones - 1; | ||
2764 | } | ||
2765 | |||
2754 | if (order < new_order || classzone_idx > new_classzone_idx) { | 2766 | if (order < new_order || classzone_idx > new_classzone_idx) { |
2755 | /* | 2767 | /* |
2756 | * Don't sleep if someone wants a larger 'order' | 2768 | * Don't sleep if someone wants a larger 'order' |
@@ -2763,7 +2775,7 @@ static int kswapd(void *p) | |||
2763 | order = pgdat->kswapd_max_order; | 2775 | order = pgdat->kswapd_max_order; |
2764 | classzone_idx = pgdat->classzone_idx; | 2776 | classzone_idx = pgdat->classzone_idx; |
2765 | pgdat->kswapd_max_order = 0; | 2777 | pgdat->kswapd_max_order = 0; |
2766 | pgdat->classzone_idx = MAX_NR_ZONES - 1; | 2778 | pgdat->classzone_idx = pgdat->nr_zones - 1; |
2767 | } | 2779 | } |
2768 | 2780 | ||
2769 | ret = try_to_freeze(); | 2781 | ret = try_to_freeze(); |