diff options
author | Mel Gorman <mgorman@techsingularity.net> | 2016-09-01 19:14:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-09-01 20:52:01 -0400 |
commit | 6aa303defb7454a2520c4ddcdf6b081f62a15890 (patch) | |
tree | f29799a63374ed8b39114c8f55bc10f52b679737 /mm/vmscan.c | |
parent | e6173ba42bbdba05fd4f3021c0beda0506271507 (diff) |
mm, vmscan: only allocate and reclaim from zones with pages managed by the buddy allocator
Firmware Assisted Dump (FA_DUMP) on ppc64 reserves substantial amounts
of memory when booting a secondary kernel. Srikar Dronamraju reported
that multiple nodes may have no memory managed by the buddy allocator
but still return true for populated_zone().
Commit 1d82de618ddd ("mm, vmscan: make kswapd reclaim in terms of
nodes") was reported to cause kswapd to spin at 100% CPU usage when
fadump was enabled. The old code happened to deal with the situation of
a populated node with zero free pages by co-incidence but the current
code tries to reclaim populated zones without realising that is
impossible.
We cannot just convert populated_zone() as many existing users really
need to check for present_pages. This patch introduces a managed_zone()
helper and uses it in the few cases where it is critical that the check
is made for managed pages -- zonelist construction and page reclaim.
Link: http://lkml.kernel.org/r/20160831195104.GB8119@techsingularity.net
Signed-off-by: Mel Gorman <mgorman@techsingularity.net>
Reported-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Tested-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Acked-by: Michal Hocko <mhocko@suse.com>
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 | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 374d95d04178..b1e12a1ea9cf 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -1665,7 +1665,7 @@ static bool inactive_reclaimable_pages(struct lruvec *lruvec, | |||
1665 | 1665 | ||
1666 | for (zid = sc->reclaim_idx; zid >= 0; zid--) { | 1666 | for (zid = sc->reclaim_idx; zid >= 0; zid--) { |
1667 | zone = &pgdat->node_zones[zid]; | 1667 | zone = &pgdat->node_zones[zid]; |
1668 | if (!populated_zone(zone)) | 1668 | if (!managed_zone(zone)) |
1669 | continue; | 1669 | continue; |
1670 | 1670 | ||
1671 | if (zone_page_state_snapshot(zone, NR_ZONE_LRU_BASE + | 1671 | if (zone_page_state_snapshot(zone, NR_ZONE_LRU_BASE + |
@@ -2036,7 +2036,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file, | |||
2036 | struct zone *zone = &pgdat->node_zones[zid]; | 2036 | struct zone *zone = &pgdat->node_zones[zid]; |
2037 | unsigned long inactive_zone, active_zone; | 2037 | unsigned long inactive_zone, active_zone; |
2038 | 2038 | ||
2039 | if (!populated_zone(zone)) | 2039 | if (!managed_zone(zone)) |
2040 | continue; | 2040 | continue; |
2041 | 2041 | ||
2042 | inactive_zone = zone_page_state(zone, | 2042 | inactive_zone = zone_page_state(zone, |
@@ -2171,7 +2171,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, | |||
2171 | 2171 | ||
2172 | for (z = 0; z < MAX_NR_ZONES; z++) { | 2172 | for (z = 0; z < MAX_NR_ZONES; z++) { |
2173 | struct zone *zone = &pgdat->node_zones[z]; | 2173 | struct zone *zone = &pgdat->node_zones[z]; |
2174 | if (!populated_zone(zone)) | 2174 | if (!managed_zone(zone)) |
2175 | continue; | 2175 | continue; |
2176 | 2176 | ||
2177 | total_high_wmark += high_wmark_pages(zone); | 2177 | total_high_wmark += high_wmark_pages(zone); |
@@ -2510,7 +2510,7 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat, | |||
2510 | /* If compaction would go ahead or the allocation would succeed, stop */ | 2510 | /* If compaction would go ahead or the allocation would succeed, stop */ |
2511 | for (z = 0; z <= sc->reclaim_idx; z++) { | 2511 | for (z = 0; z <= sc->reclaim_idx; z++) { |
2512 | struct zone *zone = &pgdat->node_zones[z]; | 2512 | struct zone *zone = &pgdat->node_zones[z]; |
2513 | if (!populated_zone(zone)) | 2513 | if (!managed_zone(zone)) |
2514 | continue; | 2514 | continue; |
2515 | 2515 | ||
2516 | switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) { | 2516 | switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) { |
@@ -2840,7 +2840,7 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat) | |||
2840 | 2840 | ||
2841 | for (i = 0; i <= ZONE_NORMAL; i++) { | 2841 | for (i = 0; i <= ZONE_NORMAL; i++) { |
2842 | zone = &pgdat->node_zones[i]; | 2842 | zone = &pgdat->node_zones[i]; |
2843 | if (!populated_zone(zone) || | 2843 | if (!managed_zone(zone) || |
2844 | pgdat_reclaimable_pages(pgdat) == 0) | 2844 | pgdat_reclaimable_pages(pgdat) == 0) |
2845 | continue; | 2845 | continue; |
2846 | 2846 | ||
@@ -3141,7 +3141,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, int classzone_idx) | |||
3141 | for (i = 0; i <= classzone_idx; i++) { | 3141 | for (i = 0; i <= classzone_idx; i++) { |
3142 | struct zone *zone = pgdat->node_zones + i; | 3142 | struct zone *zone = pgdat->node_zones + i; |
3143 | 3143 | ||
3144 | if (!populated_zone(zone)) | 3144 | if (!managed_zone(zone)) |
3145 | continue; | 3145 | continue; |
3146 | 3146 | ||
3147 | if (!zone_balanced(zone, order, classzone_idx)) | 3147 | if (!zone_balanced(zone, order, classzone_idx)) |
@@ -3169,7 +3169,7 @@ static bool kswapd_shrink_node(pg_data_t *pgdat, | |||
3169 | sc->nr_to_reclaim = 0; | 3169 | sc->nr_to_reclaim = 0; |
3170 | for (z = 0; z <= sc->reclaim_idx; z++) { | 3170 | for (z = 0; z <= sc->reclaim_idx; z++) { |
3171 | zone = pgdat->node_zones + z; | 3171 | zone = pgdat->node_zones + z; |
3172 | if (!populated_zone(zone)) | 3172 | if (!managed_zone(zone)) |
3173 | continue; | 3173 | continue; |
3174 | 3174 | ||
3175 | sc->nr_to_reclaim += max(high_wmark_pages(zone), SWAP_CLUSTER_MAX); | 3175 | sc->nr_to_reclaim += max(high_wmark_pages(zone), SWAP_CLUSTER_MAX); |
@@ -3242,7 +3242,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx) | |||
3242 | if (buffer_heads_over_limit) { | 3242 | if (buffer_heads_over_limit) { |
3243 | for (i = MAX_NR_ZONES - 1; i >= 0; i--) { | 3243 | for (i = MAX_NR_ZONES - 1; i >= 0; i--) { |
3244 | zone = pgdat->node_zones + i; | 3244 | zone = pgdat->node_zones + i; |
3245 | if (!populated_zone(zone)) | 3245 | if (!managed_zone(zone)) |
3246 | continue; | 3246 | continue; |
3247 | 3247 | ||
3248 | sc.reclaim_idx = i; | 3248 | sc.reclaim_idx = i; |
@@ -3262,7 +3262,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx) | |||
3262 | */ | 3262 | */ |
3263 | for (i = classzone_idx; i >= 0; i--) { | 3263 | for (i = classzone_idx; i >= 0; i--) { |
3264 | zone = pgdat->node_zones + i; | 3264 | zone = pgdat->node_zones + i; |
3265 | if (!populated_zone(zone)) | 3265 | if (!managed_zone(zone)) |
3266 | continue; | 3266 | continue; |
3267 | 3267 | ||
3268 | if (zone_balanced(zone, sc.order, classzone_idx)) | 3268 | if (zone_balanced(zone, sc.order, classzone_idx)) |
@@ -3508,7 +3508,7 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) | |||
3508 | pg_data_t *pgdat; | 3508 | pg_data_t *pgdat; |
3509 | int z; | 3509 | int z; |
3510 | 3510 | ||
3511 | if (!populated_zone(zone)) | 3511 | if (!managed_zone(zone)) |
3512 | return; | 3512 | return; |
3513 | 3513 | ||
3514 | if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL)) | 3514 | if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL)) |
@@ -3522,7 +3522,7 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) | |||
3522 | /* Only wake kswapd if all zones are unbalanced */ | 3522 | /* Only wake kswapd if all zones are unbalanced */ |
3523 | for (z = 0; z <= classzone_idx; z++) { | 3523 | for (z = 0; z <= classzone_idx; z++) { |
3524 | zone = pgdat->node_zones + z; | 3524 | zone = pgdat->node_zones + z; |
3525 | if (!populated_zone(zone)) | 3525 | if (!managed_zone(zone)) |
3526 | continue; | 3526 | continue; |
3527 | 3527 | ||
3528 | if (zone_balanced(zone, order, classzone_idx)) | 3528 | if (zone_balanced(zone, order, classzone_idx)) |