diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 110 |
1 files changed, 56 insertions, 54 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 556859fec4ef..d0e57a3cda18 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -776,7 +776,8 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page) | |||
776 | /* threshold event is triggered in finer grain than soft limit */ | 776 | /* threshold event is triggered in finer grain than soft limit */ |
777 | if (unlikely(mem_cgroup_event_ratelimit(memcg, | 777 | if (unlikely(mem_cgroup_event_ratelimit(memcg, |
778 | MEM_CGROUP_TARGET_THRESH))) { | 778 | MEM_CGROUP_TARGET_THRESH))) { |
779 | bool do_softlimit, do_numainfo; | 779 | bool do_softlimit; |
780 | bool do_numainfo __maybe_unused; | ||
780 | 781 | ||
781 | do_softlimit = mem_cgroup_event_ratelimit(memcg, | 782 | do_softlimit = mem_cgroup_event_ratelimit(memcg, |
782 | MEM_CGROUP_TARGET_SOFTLIMIT); | 783 | MEM_CGROUP_TARGET_SOFTLIMIT); |
@@ -1041,6 +1042,19 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page, | |||
1041 | 1042 | ||
1042 | pc = lookup_page_cgroup(page); | 1043 | pc = lookup_page_cgroup(page); |
1043 | memcg = pc->mem_cgroup; | 1044 | memcg = pc->mem_cgroup; |
1045 | |||
1046 | /* | ||
1047 | * Surreptitiously switch any uncharged page to root: | ||
1048 | * an uncharged page off lru does nothing to secure | ||
1049 | * its former mem_cgroup from sudden removal. | ||
1050 | * | ||
1051 | * Our caller holds lru_lock, and PageCgroupUsed is updated | ||
1052 | * under page_cgroup lock: between them, they make all uses | ||
1053 | * of pc->mem_cgroup safe. | ||
1054 | */ | ||
1055 | if (!PageCgroupUsed(pc) && memcg != root_mem_cgroup) | ||
1056 | pc->mem_cgroup = memcg = root_mem_cgroup; | ||
1057 | |||
1044 | mz = page_cgroup_zoneinfo(memcg, page); | 1058 | mz = page_cgroup_zoneinfo(memcg, page); |
1045 | /* compound_order() is stabilized through lru_lock */ | 1059 | /* compound_order() is stabilized through lru_lock */ |
1046 | MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page); | 1060 | MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page); |
@@ -2407,8 +2421,12 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2407 | struct page *page, | 2421 | struct page *page, |
2408 | unsigned int nr_pages, | 2422 | unsigned int nr_pages, |
2409 | struct page_cgroup *pc, | 2423 | struct page_cgroup *pc, |
2410 | enum charge_type ctype) | 2424 | enum charge_type ctype, |
2425 | bool lrucare) | ||
2411 | { | 2426 | { |
2427 | struct zone *uninitialized_var(zone); | ||
2428 | bool was_on_lru = false; | ||
2429 | |||
2412 | lock_page_cgroup(pc); | 2430 | lock_page_cgroup(pc); |
2413 | if (unlikely(PageCgroupUsed(pc))) { | 2431 | if (unlikely(PageCgroupUsed(pc))) { |
2414 | unlock_page_cgroup(pc); | 2432 | unlock_page_cgroup(pc); |
@@ -2419,6 +2437,21 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2419 | * we don't need page_cgroup_lock about tail pages, becase they are not | 2437 | * we don't need page_cgroup_lock about tail pages, becase they are not |
2420 | * accessed by any other context at this point. | 2438 | * accessed by any other context at this point. |
2421 | */ | 2439 | */ |
2440 | |||
2441 | /* | ||
2442 | * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page | ||
2443 | * may already be on some other mem_cgroup's LRU. Take care of it. | ||
2444 | */ | ||
2445 | if (lrucare) { | ||
2446 | zone = page_zone(page); | ||
2447 | spin_lock_irq(&zone->lru_lock); | ||
2448 | if (PageLRU(page)) { | ||
2449 | ClearPageLRU(page); | ||
2450 | del_page_from_lru_list(zone, page, page_lru(page)); | ||
2451 | was_on_lru = true; | ||
2452 | } | ||
2453 | } | ||
2454 | |||
2422 | pc->mem_cgroup = memcg; | 2455 | pc->mem_cgroup = memcg; |
2423 | /* | 2456 | /* |
2424 | * We access a page_cgroup asynchronously without lock_page_cgroup(). | 2457 | * We access a page_cgroup asynchronously without lock_page_cgroup(). |
@@ -2442,9 +2475,18 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2442 | break; | 2475 | break; |
2443 | } | 2476 | } |
2444 | 2477 | ||
2478 | if (lrucare) { | ||
2479 | if (was_on_lru) { | ||
2480 | VM_BUG_ON(PageLRU(page)); | ||
2481 | SetPageLRU(page); | ||
2482 | add_page_to_lru_list(zone, page, page_lru(page)); | ||
2483 | } | ||
2484 | spin_unlock_irq(&zone->lru_lock); | ||
2485 | } | ||
2486 | |||
2445 | mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages); | 2487 | mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages); |
2446 | unlock_page_cgroup(pc); | 2488 | unlock_page_cgroup(pc); |
2447 | WARN_ON_ONCE(PageLRU(page)); | 2489 | |
2448 | /* | 2490 | /* |
2449 | * "charge_statistics" updated event counter. Then, check it. | 2491 | * "charge_statistics" updated event counter. Then, check it. |
2450 | * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree. | 2492 | * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree. |
@@ -2642,7 +2684,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
2642 | ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom); | 2684 | ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom); |
2643 | if (ret == -ENOMEM) | 2685 | if (ret == -ENOMEM) |
2644 | return ret; | 2686 | return ret; |
2645 | __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype); | 2687 | __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype, false); |
2646 | return 0; | 2688 | return 0; |
2647 | } | 2689 | } |
2648 | 2690 | ||
@@ -2662,35 +2704,6 @@ static void | |||
2662 | __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr, | 2704 | __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr, |
2663 | enum charge_type ctype); | 2705 | enum charge_type ctype); |
2664 | 2706 | ||
2665 | static void | ||
2666 | __mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg, | ||
2667 | enum charge_type ctype) | ||
2668 | { | ||
2669 | struct page_cgroup *pc = lookup_page_cgroup(page); | ||
2670 | struct zone *zone = page_zone(page); | ||
2671 | unsigned long flags; | ||
2672 | bool removed = false; | ||
2673 | |||
2674 | /* | ||
2675 | * In some case, SwapCache, FUSE(splice_buf->radixtree), the page | ||
2676 | * is already on LRU. It means the page may on some other page_cgroup's | ||
2677 | * LRU. Take care of it. | ||
2678 | */ | ||
2679 | spin_lock_irqsave(&zone->lru_lock, flags); | ||
2680 | if (PageLRU(page)) { | ||
2681 | del_page_from_lru_list(zone, page, page_lru(page)); | ||
2682 | ClearPageLRU(page); | ||
2683 | removed = true; | ||
2684 | } | ||
2685 | __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype); | ||
2686 | if (removed) { | ||
2687 | add_page_to_lru_list(zone, page, page_lru(page)); | ||
2688 | SetPageLRU(page); | ||
2689 | } | ||
2690 | spin_unlock_irqrestore(&zone->lru_lock, flags); | ||
2691 | return; | ||
2692 | } | ||
2693 | |||
2694 | int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm, | 2707 | int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm, |
2695 | gfp_t gfp_mask) | 2708 | gfp_t gfp_mask) |
2696 | { | 2709 | { |
@@ -2768,13 +2781,16 @@ static void | |||
2768 | __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg, | 2781 | __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg, |
2769 | enum charge_type ctype) | 2782 | enum charge_type ctype) |
2770 | { | 2783 | { |
2784 | struct page_cgroup *pc; | ||
2785 | |||
2771 | if (mem_cgroup_disabled()) | 2786 | if (mem_cgroup_disabled()) |
2772 | return; | 2787 | return; |
2773 | if (!memcg) | 2788 | if (!memcg) |
2774 | return; | 2789 | return; |
2775 | cgroup_exclude_rmdir(&memcg->css); | 2790 | cgroup_exclude_rmdir(&memcg->css); |
2776 | 2791 | ||
2777 | __mem_cgroup_commit_charge_lrucare(page, memcg, ctype); | 2792 | pc = lookup_page_cgroup(page); |
2793 | __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype, true); | ||
2778 | /* | 2794 | /* |
2779 | * Now swap is on-memory. This means this page may be | 2795 | * Now swap is on-memory. This means this page may be |
2780 | * counted both as mem and swap....double count. | 2796 | * counted both as mem and swap....double count. |
@@ -3026,23 +3042,6 @@ void mem_cgroup_uncharge_end(void) | |||
3026 | batch->memcg = NULL; | 3042 | batch->memcg = NULL; |
3027 | } | 3043 | } |
3028 | 3044 | ||
3029 | /* | ||
3030 | * A function for resetting pc->mem_cgroup for newly allocated pages. | ||
3031 | * This function should be called if the newpage will be added to LRU | ||
3032 | * before start accounting. | ||
3033 | */ | ||
3034 | void mem_cgroup_reset_owner(struct page *newpage) | ||
3035 | { | ||
3036 | struct page_cgroup *pc; | ||
3037 | |||
3038 | if (mem_cgroup_disabled()) | ||
3039 | return; | ||
3040 | |||
3041 | pc = lookup_page_cgroup(newpage); | ||
3042 | VM_BUG_ON(PageCgroupUsed(pc)); | ||
3043 | pc->mem_cgroup = root_mem_cgroup; | ||
3044 | } | ||
3045 | |||
3046 | #ifdef CONFIG_SWAP | 3045 | #ifdef CONFIG_SWAP |
3047 | /* | 3046 | /* |
3048 | * called after __delete_from_swap_cache() and drop "page" account. | 3047 | * called after __delete_from_swap_cache() and drop "page" account. |
@@ -3247,7 +3246,7 @@ int mem_cgroup_prepare_migration(struct page *page, | |||
3247 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; | 3246 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; |
3248 | else | 3247 | else |
3249 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; | 3248 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; |
3250 | __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype); | 3249 | __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype, false); |
3251 | return ret; | 3250 | return ret; |
3252 | } | 3251 | } |
3253 | 3252 | ||
@@ -3331,7 +3330,7 @@ void mem_cgroup_replace_page_cache(struct page *oldpage, | |||
3331 | * the newpage may be on LRU(or pagevec for LRU) already. We lock | 3330 | * the newpage may be on LRU(or pagevec for LRU) already. We lock |
3332 | * LRU while we overwrite pc->mem_cgroup. | 3331 | * LRU while we overwrite pc->mem_cgroup. |
3333 | */ | 3332 | */ |
3334 | __mem_cgroup_commit_charge_lrucare(newpage, memcg, type); | 3333 | __mem_cgroup_commit_charge(memcg, newpage, 1, pc, type, true); |
3335 | } | 3334 | } |
3336 | 3335 | ||
3337 | #ifdef CONFIG_DEBUG_VM | 3336 | #ifdef CONFIG_DEBUG_VM |
@@ -4413,6 +4412,9 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp, | |||
4413 | */ | 4412 | */ |
4414 | BUG_ON(!thresholds); | 4413 | BUG_ON(!thresholds); |
4415 | 4414 | ||
4415 | if (!thresholds->primary) | ||
4416 | goto unlock; | ||
4417 | |||
4416 | usage = mem_cgroup_usage(memcg, type == _MEMSWAP); | 4418 | usage = mem_cgroup_usage(memcg, type == _MEMSWAP); |
4417 | 4419 | ||
4418 | /* Check if a threshold crossed before removing */ | 4420 | /* Check if a threshold crossed before removing */ |
@@ -4461,7 +4463,7 @@ swap_buffers: | |||
4461 | 4463 | ||
4462 | /* To be sure that nobody uses thresholds */ | 4464 | /* To be sure that nobody uses thresholds */ |
4463 | synchronize_rcu(); | 4465 | synchronize_rcu(); |
4464 | 4466 | unlock: | |
4465 | mutex_unlock(&memcg->thresholds_lock); | 4467 | mutex_unlock(&memcg->thresholds_lock); |
4466 | } | 4468 | } |
4467 | 4469 | ||