diff options
-rw-r--r-- | include/linux/memcontrol.h | 19 | ||||
-rw-r--r-- | include/linux/mmzone.h | 4 | ||||
-rw-r--r-- | include/linux/swap.h | 2 | ||||
-rw-r--r-- | mm/memcontrol.c | 4 | ||||
-rw-r--r-- | mm/page_alloc.c | 2 | ||||
-rw-r--r-- | mm/vmscan.c | 61 | ||||
-rw-r--r-- | mm/workingset.c | 6 |
7 files changed, 54 insertions, 44 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 6d2321c148cd..f4963ee4fdbc 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h | |||
@@ -324,22 +324,23 @@ mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone) | |||
324 | } | 324 | } |
325 | 325 | ||
326 | /** | 326 | /** |
327 | * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg | 327 | * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone |
328 | * @node: node of the wanted lruvec | ||
328 | * @zone: zone of the wanted lruvec | 329 | * @zone: zone of the wanted lruvec |
329 | * @memcg: memcg of the wanted lruvec | 330 | * @memcg: memcg of the wanted lruvec |
330 | * | 331 | * |
331 | * Returns the lru list vector holding pages for the given @zone and | 332 | * Returns the lru list vector holding pages for a given @node or a given |
332 | * @mem. This can be the global zone lruvec, if the memory controller | 333 | * @memcg and @zone. This can be the node lruvec, if the memory controller |
333 | * is disabled. | 334 | * is disabled. |
334 | */ | 335 | */ |
335 | static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone, | 336 | static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, |
336 | struct mem_cgroup *memcg) | 337 | struct zone *zone, struct mem_cgroup *memcg) |
337 | { | 338 | { |
338 | struct mem_cgroup_per_zone *mz; | 339 | struct mem_cgroup_per_zone *mz; |
339 | struct lruvec *lruvec; | 340 | struct lruvec *lruvec; |
340 | 341 | ||
341 | if (mem_cgroup_disabled()) { | 342 | if (mem_cgroup_disabled()) { |
342 | lruvec = zone_lruvec(zone); | 343 | lruvec = node_lruvec(pgdat); |
343 | goto out; | 344 | goto out; |
344 | } | 345 | } |
345 | 346 | ||
@@ -609,10 +610,10 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new) | |||
609 | { | 610 | { |
610 | } | 611 | } |
611 | 612 | ||
612 | static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone, | 613 | static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, |
613 | struct mem_cgroup *memcg) | 614 | struct zone *zone, struct mem_cgroup *memcg) |
614 | { | 615 | { |
615 | return zone_lruvec(zone); | 616 | return node_lruvec(pgdat); |
616 | } | 617 | } |
617 | 618 | ||
618 | static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, | 619 | static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, |
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 4062fa74526f..895c365e3259 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -739,9 +739,9 @@ static inline spinlock_t *zone_lru_lock(struct zone *zone) | |||
739 | return &zone->zone_pgdat->lru_lock; | 739 | return &zone->zone_pgdat->lru_lock; |
740 | } | 740 | } |
741 | 741 | ||
742 | static inline struct lruvec *zone_lruvec(struct zone *zone) | 742 | static inline struct lruvec *node_lruvec(struct pglist_data *pgdat) |
743 | { | 743 | { |
744 | return &zone->zone_pgdat->lruvec; | 744 | return &pgdat->lruvec; |
745 | } | 745 | } |
746 | 746 | ||
747 | static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) | 747 | static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) |
diff --git a/include/linux/swap.h b/include/linux/swap.h index 916e2eddecd6..0ad616d7c381 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
@@ -316,7 +316,7 @@ extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, | |||
316 | unsigned long nr_pages, | 316 | unsigned long nr_pages, |
317 | gfp_t gfp_mask, | 317 | gfp_t gfp_mask, |
318 | bool may_swap); | 318 | bool may_swap); |
319 | extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem, | 319 | extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem, |
320 | gfp_t gfp_mask, bool noswap, | 320 | gfp_t gfp_mask, bool noswap, |
321 | struct zone *zone, | 321 | struct zone *zone, |
322 | unsigned long *nr_scanned); | 322 | unsigned long *nr_scanned); |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 50c86ad121bc..c9ebec98e92a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1432,8 +1432,8 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, | |||
1432 | } | 1432 | } |
1433 | continue; | 1433 | continue; |
1434 | } | 1434 | } |
1435 | total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false, | 1435 | total += mem_cgroup_shrink_node(victim, gfp_mask, false, |
1436 | zone, &nr_scanned); | 1436 | zone, &nr_scanned); |
1437 | *total_scanned += nr_scanned; | 1437 | *total_scanned += nr_scanned; |
1438 | if (!soft_limit_excess(root_memcg)) | 1438 | if (!soft_limit_excess(root_memcg)) |
1439 | break; | 1439 | break; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 81586410c59c..749b3c358ead 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -5911,6 +5911,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat) | |||
5911 | #endif | 5911 | #endif |
5912 | pgdat_page_ext_init(pgdat); | 5912 | pgdat_page_ext_init(pgdat); |
5913 | spin_lock_init(&pgdat->lru_lock); | 5913 | spin_lock_init(&pgdat->lru_lock); |
5914 | lruvec_init(node_lruvec(pgdat)); | ||
5914 | 5915 | ||
5915 | for (j = 0; j < MAX_NR_ZONES; j++) { | 5916 | for (j = 0; j < MAX_NR_ZONES; j++) { |
5916 | struct zone *zone = pgdat->node_zones + j; | 5917 | struct zone *zone = pgdat->node_zones + j; |
@@ -5973,7 +5974,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat) | |||
5973 | /* For bootup, initialized properly in watermark setup */ | 5974 | /* For bootup, initialized properly in watermark setup */ |
5974 | mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages); | 5975 | mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages); |
5975 | 5976 | ||
5976 | lruvec_init(zone_lruvec(zone)); | ||
5977 | if (!size) | 5977 | if (!size) |
5978 | continue; | 5978 | continue; |
5979 | 5979 | ||
diff --git a/mm/vmscan.c b/mm/vmscan.c index b7a276f4b1b0..46f7a71ed13b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -2224,12 +2224,13 @@ static inline void init_tlb_ubc(void) | |||
2224 | #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ | 2224 | #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ |
2225 | 2225 | ||
2226 | /* | 2226 | /* |
2227 | * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. | 2227 | * This is a basic per-node page freer. Used by both kswapd and direct reclaim. |
2228 | */ | 2228 | */ |
2229 | static void shrink_zone_memcg(struct zone *zone, struct mem_cgroup *memcg, | 2229 | static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg, |
2230 | struct scan_control *sc, unsigned long *lru_pages) | 2230 | struct scan_control *sc, unsigned long *lru_pages) |
2231 | { | 2231 | { |
2232 | struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg); | 2232 | struct zone *zone = &pgdat->node_zones[sc->reclaim_idx]; |
2233 | struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, zone, memcg); | ||
2233 | unsigned long nr[NR_LRU_LISTS]; | 2234 | unsigned long nr[NR_LRU_LISTS]; |
2234 | unsigned long targets[NR_LRU_LISTS]; | 2235 | unsigned long targets[NR_LRU_LISTS]; |
2235 | unsigned long nr_to_scan; | 2236 | unsigned long nr_to_scan; |
@@ -2362,13 +2363,14 @@ static bool in_reclaim_compaction(struct scan_control *sc) | |||
2362 | * calls try_to_compact_zone() that it will have enough free pages to succeed. | 2363 | * calls try_to_compact_zone() that it will have enough free pages to succeed. |
2363 | * It will give up earlier than that if there is difficulty reclaiming pages. | 2364 | * It will give up earlier than that if there is difficulty reclaiming pages. |
2364 | */ | 2365 | */ |
2365 | static inline bool should_continue_reclaim(struct zone *zone, | 2366 | static inline bool should_continue_reclaim(struct pglist_data *pgdat, |
2366 | unsigned long nr_reclaimed, | 2367 | unsigned long nr_reclaimed, |
2367 | unsigned long nr_scanned, | 2368 | unsigned long nr_scanned, |
2368 | struct scan_control *sc) | 2369 | struct scan_control *sc) |
2369 | { | 2370 | { |
2370 | unsigned long pages_for_compaction; | 2371 | unsigned long pages_for_compaction; |
2371 | unsigned long inactive_lru_pages; | 2372 | unsigned long inactive_lru_pages; |
2373 | int z; | ||
2372 | 2374 | ||
2373 | /* If not in reclaim/compaction mode, stop */ | 2375 | /* If not in reclaim/compaction mode, stop */ |
2374 | if (!in_reclaim_compaction(sc)) | 2376 | if (!in_reclaim_compaction(sc)) |
@@ -2402,21 +2404,29 @@ static inline bool should_continue_reclaim(struct zone *zone, | |||
2402 | * inactive lists are large enough, continue reclaiming | 2404 | * inactive lists are large enough, continue reclaiming |
2403 | */ | 2405 | */ |
2404 | pages_for_compaction = (2UL << sc->order); | 2406 | pages_for_compaction = (2UL << sc->order); |
2405 | inactive_lru_pages = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE); | 2407 | inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE); |
2406 | if (get_nr_swap_pages() > 0) | 2408 | if (get_nr_swap_pages() > 0) |
2407 | inactive_lru_pages += node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON); | 2409 | inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON); |
2408 | if (sc->nr_reclaimed < pages_for_compaction && | 2410 | if (sc->nr_reclaimed < pages_for_compaction && |
2409 | inactive_lru_pages > pages_for_compaction) | 2411 | inactive_lru_pages > pages_for_compaction) |
2410 | return true; | 2412 | return true; |
2411 | 2413 | ||
2412 | /* If compaction would go ahead or the allocation would succeed, stop */ | 2414 | /* If compaction would go ahead or the allocation would succeed, stop */ |
2413 | switch (compaction_suitable(zone, sc->order, 0, 0)) { | 2415 | for (z = 0; z <= sc->reclaim_idx; z++) { |
2414 | case COMPACT_PARTIAL: | 2416 | struct zone *zone = &pgdat->node_zones[z]; |
2415 | case COMPACT_CONTINUE: | 2417 | if (!populated_zone(zone)) |
2416 | return false; | 2418 | continue; |
2417 | default: | 2419 | |
2418 | return true; | 2420 | switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) { |
2421 | case COMPACT_PARTIAL: | ||
2422 | case COMPACT_CONTINUE: | ||
2423 | return false; | ||
2424 | default: | ||
2425 | /* check next zone */ | ||
2426 | ; | ||
2427 | } | ||
2419 | } | 2428 | } |
2429 | return true; | ||
2420 | } | 2430 | } |
2421 | 2431 | ||
2422 | static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | 2432 | static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, |
@@ -2425,15 +2435,14 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | |||
2425 | struct reclaim_state *reclaim_state = current->reclaim_state; | 2435 | struct reclaim_state *reclaim_state = current->reclaim_state; |
2426 | unsigned long nr_reclaimed, nr_scanned; | 2436 | unsigned long nr_reclaimed, nr_scanned; |
2427 | bool reclaimable = false; | 2437 | bool reclaimable = false; |
2428 | struct zone *zone = &pgdat->node_zones[classzone_idx]; | ||
2429 | 2438 | ||
2430 | do { | 2439 | do { |
2431 | struct mem_cgroup *root = sc->target_mem_cgroup; | 2440 | struct mem_cgroup *root = sc->target_mem_cgroup; |
2432 | struct mem_cgroup_reclaim_cookie reclaim = { | 2441 | struct mem_cgroup_reclaim_cookie reclaim = { |
2433 | .zone = zone, | 2442 | .zone = &pgdat->node_zones[classzone_idx], |
2434 | .priority = sc->priority, | 2443 | .priority = sc->priority, |
2435 | }; | 2444 | }; |
2436 | unsigned long zone_lru_pages = 0; | 2445 | unsigned long node_lru_pages = 0; |
2437 | struct mem_cgroup *memcg; | 2446 | struct mem_cgroup *memcg; |
2438 | 2447 | ||
2439 | nr_reclaimed = sc->nr_reclaimed; | 2448 | nr_reclaimed = sc->nr_reclaimed; |
@@ -2454,11 +2463,11 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | |||
2454 | reclaimed = sc->nr_reclaimed; | 2463 | reclaimed = sc->nr_reclaimed; |
2455 | scanned = sc->nr_scanned; | 2464 | scanned = sc->nr_scanned; |
2456 | 2465 | ||
2457 | shrink_zone_memcg(zone, memcg, sc, &lru_pages); | 2466 | shrink_node_memcg(pgdat, memcg, sc, &lru_pages); |
2458 | zone_lru_pages += lru_pages; | 2467 | node_lru_pages += lru_pages; |
2459 | 2468 | ||
2460 | if (!global_reclaim(sc)) | 2469 | if (!global_reclaim(sc)) |
2461 | shrink_slab(sc->gfp_mask, zone_to_nid(zone), | 2470 | shrink_slab(sc->gfp_mask, pgdat->node_id, |
2462 | memcg, sc->nr_scanned - scanned, | 2471 | memcg, sc->nr_scanned - scanned, |
2463 | lru_pages); | 2472 | lru_pages); |
2464 | 2473 | ||
@@ -2470,7 +2479,7 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | |||
2470 | /* | 2479 | /* |
2471 | * Direct reclaim and kswapd have to scan all memory | 2480 | * Direct reclaim and kswapd have to scan all memory |
2472 | * cgroups to fulfill the overall scan target for the | 2481 | * cgroups to fulfill the overall scan target for the |
2473 | * zone. | 2482 | * node. |
2474 | * | 2483 | * |
2475 | * Limit reclaim, on the other hand, only cares about | 2484 | * Limit reclaim, on the other hand, only cares about |
2476 | * nr_to_reclaim pages to be reclaimed and it will | 2485 | * nr_to_reclaim pages to be reclaimed and it will |
@@ -2489,9 +2498,9 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | |||
2489 | * the eligible LRU pages were scanned. | 2498 | * the eligible LRU pages were scanned. |
2490 | */ | 2499 | */ |
2491 | if (global_reclaim(sc)) | 2500 | if (global_reclaim(sc)) |
2492 | shrink_slab(sc->gfp_mask, zone_to_nid(zone), NULL, | 2501 | shrink_slab(sc->gfp_mask, pgdat->node_id, NULL, |
2493 | sc->nr_scanned - nr_scanned, | 2502 | sc->nr_scanned - nr_scanned, |
2494 | zone_lru_pages); | 2503 | node_lru_pages); |
2495 | 2504 | ||
2496 | if (reclaim_state) { | 2505 | if (reclaim_state) { |
2497 | sc->nr_reclaimed += reclaim_state->reclaimed_slab; | 2506 | sc->nr_reclaimed += reclaim_state->reclaimed_slab; |
@@ -2506,7 +2515,7 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc, | |||
2506 | if (sc->nr_reclaimed - nr_reclaimed) | 2515 | if (sc->nr_reclaimed - nr_reclaimed) |
2507 | reclaimable = true; | 2516 | reclaimable = true; |
2508 | 2517 | ||
2509 | } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed, | 2518 | } while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed, |
2510 | sc->nr_scanned - nr_scanned, sc)); | 2519 | sc->nr_scanned - nr_scanned, sc)); |
2511 | 2520 | ||
2512 | return reclaimable; | 2521 | return reclaimable; |
@@ -2906,7 +2915,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, | |||
2906 | 2915 | ||
2907 | #ifdef CONFIG_MEMCG | 2916 | #ifdef CONFIG_MEMCG |
2908 | 2917 | ||
2909 | unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg, | 2918 | unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg, |
2910 | gfp_t gfp_mask, bool noswap, | 2919 | gfp_t gfp_mask, bool noswap, |
2911 | struct zone *zone, | 2920 | struct zone *zone, |
2912 | unsigned long *nr_scanned) | 2921 | unsigned long *nr_scanned) |
@@ -2931,11 +2940,11 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg, | |||
2931 | /* | 2940 | /* |
2932 | * NOTE: Although we can get the priority field, using it | 2941 | * NOTE: Although we can get the priority field, using it |
2933 | * here is not a good idea, since it limits the pages we can scan. | 2942 | * here is not a good idea, since it limits the pages we can scan. |
2934 | * if we don't reclaim here, the shrink_zone from balance_pgdat | 2943 | * if we don't reclaim here, the shrink_node from balance_pgdat |
2935 | * will pick up pages from other mem cgroup's as well. We hack | 2944 | * will pick up pages from other mem cgroup's as well. We hack |
2936 | * the priority and make it zero. | 2945 | * the priority and make it zero. |
2937 | */ | 2946 | */ |
2938 | shrink_zone_memcg(zone, memcg, &sc, &lru_pages); | 2947 | shrink_node_memcg(zone->zone_pgdat, memcg, &sc, &lru_pages); |
2939 | 2948 | ||
2940 | trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed); | 2949 | trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed); |
2941 | 2950 | ||
@@ -2994,7 +3003,7 @@ static void age_active_anon(struct pglist_data *pgdat, | |||
2994 | 3003 | ||
2995 | memcg = mem_cgroup_iter(NULL, NULL, NULL); | 3004 | memcg = mem_cgroup_iter(NULL, NULL, NULL); |
2996 | do { | 3005 | do { |
2997 | struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg); | 3006 | struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, zone, memcg); |
2998 | 3007 | ||
2999 | if (inactive_list_is_low(lruvec, false)) | 3008 | if (inactive_list_is_low(lruvec, false)) |
3000 | shrink_active_list(SWAP_CLUSTER_MAX, lruvec, | 3009 | shrink_active_list(SWAP_CLUSTER_MAX, lruvec, |
diff --git a/mm/workingset.c b/mm/workingset.c index 7820a7e1ca98..df0dacaf54ee 100644 --- a/mm/workingset.c +++ b/mm/workingset.c | |||
@@ -218,7 +218,7 @@ void *workingset_eviction(struct address_space *mapping, struct page *page) | |||
218 | VM_BUG_ON_PAGE(page_count(page), page); | 218 | VM_BUG_ON_PAGE(page_count(page), page); |
219 | VM_BUG_ON_PAGE(!PageLocked(page), page); | 219 | VM_BUG_ON_PAGE(!PageLocked(page), page); |
220 | 220 | ||
221 | lruvec = mem_cgroup_zone_lruvec(zone, memcg); | 221 | lruvec = mem_cgroup_lruvec(zone->zone_pgdat, zone, memcg); |
222 | eviction = atomic_long_inc_return(&lruvec->inactive_age); | 222 | eviction = atomic_long_inc_return(&lruvec->inactive_age); |
223 | return pack_shadow(memcgid, zone, eviction); | 223 | return pack_shadow(memcgid, zone, eviction); |
224 | } | 224 | } |
@@ -267,7 +267,7 @@ bool workingset_refault(void *shadow) | |||
267 | rcu_read_unlock(); | 267 | rcu_read_unlock(); |
268 | return false; | 268 | return false; |
269 | } | 269 | } |
270 | lruvec = mem_cgroup_zone_lruvec(zone, memcg); | 270 | lruvec = mem_cgroup_lruvec(zone->zone_pgdat, zone, memcg); |
271 | refault = atomic_long_read(&lruvec->inactive_age); | 271 | refault = atomic_long_read(&lruvec->inactive_age); |
272 | active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE); | 272 | active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE); |
273 | rcu_read_unlock(); | 273 | rcu_read_unlock(); |
@@ -319,7 +319,7 @@ void workingset_activation(struct page *page) | |||
319 | memcg = page_memcg_rcu(page); | 319 | memcg = page_memcg_rcu(page); |
320 | if (!mem_cgroup_disabled() && !memcg) | 320 | if (!mem_cgroup_disabled() && !memcg) |
321 | goto out; | 321 | goto out; |
322 | lruvec = mem_cgroup_zone_lruvec(page_zone(page), memcg); | 322 | lruvec = mem_cgroup_lruvec(page_pgdat(page), page_zone(page), memcg); |
323 | atomic_long_inc(&lruvec->inactive_age); | 323 | atomic_long_inc(&lruvec->inactive_age); |
324 | out: | 324 | out: |
325 | rcu_read_unlock(); | 325 | rcu_read_unlock(); |