Commit b24028572fb69e9dd6de8c359eba2b2c66baa889
Committed by
Linus Torvalds
1 parent
ca464d69b1
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
memcg: remove PCG_CACHE page_cgroup flag
We record 'the page is cache' with the PCG_CACHE bit in page_cgroup. Here, "CACHE" means anonymous user pages (and SwapCache). This doesn't include shmem. Considering callers, at charge/uncharge, the caller should know what the page is and we don't need to record it by using one bit per page. This patch removes PCG_CACHE bit and make callers of mem_cgroup_charge_statistics() to specify what the page is. About page migration: Mapping of the used page is not touched during migra tion (see page_remove_rmap) so we can rely on it and push the correct charge type down to __mem_cgroup_uncharge_common from end_migration for unused page. The force flag was misleading was abused for skipping the needless page_mapped() / PageCgroupMigration() check, as we know the unused page is no longer mapped and cleared the migration flag just a few lines up. But doing the checks is no biggie and it's not worth adding another flag just to skip them. [akpm@linux-foundation.org: checkpatch fixes] [hughd@google.com: fix PageAnon uncharging] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Michal Hocko <mhocko@suse.cz> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Hugh Dickins <hughd@google.com> Cc: Ying Han <yinghan@google.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 2 changed files with 33 additions and 32 deletions Side-by-side Diff
include/linux/page_cgroup.h
... | ... | @@ -4,7 +4,6 @@ |
4 | 4 | enum { |
5 | 5 | /* flags for mem_cgroup */ |
6 | 6 | PCG_LOCK, /* Lock for pc->mem_cgroup and following bits. */ |
7 | - PCG_CACHE, /* charged as cache */ | |
8 | 7 | PCG_USED, /* this object is in use. */ |
9 | 8 | PCG_MIGRATION, /* under page migration */ |
10 | 9 | /* flags for mem_cgroup and file and I/O status */ |
... | ... | @@ -64,11 +63,6 @@ |
64 | 63 | static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \ |
65 | 64 | { return test_and_clear_bit(PCG_##lname, &pc->flags); } |
66 | 65 | |
67 | -/* Cache flag is set only once (at allocation) */ | |
68 | -TESTPCGFLAG(Cache, CACHE) | |
69 | -CLEARPCGFLAG(Cache, CACHE) | |
70 | -SETPCGFLAG(Cache, CACHE) | |
71 | - | |
72 | 66 | TESTPCGFLAG(Used, USED) |
73 | 67 | CLEARPCGFLAG(Used, USED) |
74 | 68 | SETPCGFLAG(Used, USED) |
... | ... | @@ -85,7 +79,7 @@ |
85 | 79 | { |
86 | 80 | /* |
87 | 81 | * Don't take this lock in IRQ context. |
88 | - * This lock is for pc->mem_cgroup, USED, CACHE, MIGRATION | |
82 | + * This lock is for pc->mem_cgroup, USED, MIGRATION | |
89 | 83 | */ |
90 | 84 | bit_spin_lock(PCG_LOCK, &pc->flags); |
91 | 85 | } |
mm/memcontrol.c
... | ... | @@ -690,15 +690,19 @@ |
690 | 690 | } |
691 | 691 | |
692 | 692 | static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, |
693 | - bool file, int nr_pages) | |
693 | + bool anon, int nr_pages) | |
694 | 694 | { |
695 | 695 | preempt_disable(); |
696 | 696 | |
697 | - if (file) | |
698 | - __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE], | |
697 | + /* | |
698 | + * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is | |
699 | + * counted as CACHE even if it's on ANON LRU. | |
700 | + */ | |
701 | + if (anon) | |
702 | + __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS], | |
699 | 703 | nr_pages); |
700 | 704 | else |
701 | - __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS], | |
705 | + __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE], | |
702 | 706 | nr_pages); |
703 | 707 | |
704 | 708 | /* pagein of a big page is an event. So, ignore page size */ |
... | ... | @@ -2442,6 +2446,7 @@ |
2442 | 2446 | { |
2443 | 2447 | struct zone *uninitialized_var(zone); |
2444 | 2448 | bool was_on_lru = false; |
2449 | + bool anon; | |
2445 | 2450 | |
2446 | 2451 | lock_page_cgroup(pc); |
2447 | 2452 | if (unlikely(PageCgroupUsed(pc))) { |
... | ... | @@ -2477,19 +2482,7 @@ |
2477 | 2482 | * See mem_cgroup_add_lru_list(), etc. |
2478 | 2483 | */ |
2479 | 2484 | smp_wmb(); |
2480 | - switch (ctype) { | |
2481 | - case MEM_CGROUP_CHARGE_TYPE_CACHE: | |
2482 | - case MEM_CGROUP_CHARGE_TYPE_SHMEM: | |
2483 | - SetPageCgroupCache(pc); | |
2484 | - SetPageCgroupUsed(pc); | |
2485 | - break; | |
2486 | - case MEM_CGROUP_CHARGE_TYPE_MAPPED: | |
2487 | - ClearPageCgroupCache(pc); | |
2488 | - SetPageCgroupUsed(pc); | |
2489 | - break; | |
2490 | - default: | |
2491 | - break; | |
2492 | - } | |
2485 | + SetPageCgroupUsed(pc); | |
2493 | 2486 | |
2494 | 2487 | if (lrucare) { |
2495 | 2488 | if (was_on_lru) { |
... | ... | @@ -2500,7 +2493,12 @@ |
2500 | 2493 | spin_unlock_irq(&zone->lru_lock); |
2501 | 2494 | } |
2502 | 2495 | |
2503 | - mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages); | |
2496 | + if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED) | |
2497 | + anon = true; | |
2498 | + else | |
2499 | + anon = false; | |
2500 | + | |
2501 | + mem_cgroup_charge_statistics(memcg, anon, nr_pages); | |
2504 | 2502 | unlock_page_cgroup(pc); |
2505 | 2503 | |
2506 | 2504 | /* |
... | ... | @@ -2565,6 +2563,7 @@ |
2565 | 2563 | { |
2566 | 2564 | unsigned long flags; |
2567 | 2565 | int ret; |
2566 | + bool anon = PageAnon(page); | |
2568 | 2567 | |
2569 | 2568 | VM_BUG_ON(from == to); |
2570 | 2569 | VM_BUG_ON(PageLRU(page)); |
2571 | 2570 | |
... | ... | @@ -2593,14 +2592,14 @@ |
2593 | 2592 | __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); |
2594 | 2593 | preempt_enable(); |
2595 | 2594 | } |
2596 | - mem_cgroup_charge_statistics(from, PageCgroupCache(pc), -nr_pages); | |
2595 | + mem_cgroup_charge_statistics(from, anon, -nr_pages); | |
2597 | 2596 | if (uncharge) |
2598 | 2597 | /* This is not "cancel", but cancel_charge does all we need. */ |
2599 | 2598 | __mem_cgroup_cancel_charge(from, nr_pages); |
2600 | 2599 | |
2601 | 2600 | /* caller should have done css_get */ |
2602 | 2601 | pc->mem_cgroup = to; |
2603 | - mem_cgroup_charge_statistics(to, PageCgroupCache(pc), nr_pages); | |
2602 | + mem_cgroup_charge_statistics(to, anon, nr_pages); | |
2604 | 2603 | /* |
2605 | 2604 | * We charges against "to" which may not have any tasks. Then, "to" |
2606 | 2605 | * can be under rmdir(). But in current implementation, caller of |
... | ... | @@ -2921,6 +2920,7 @@ |
2921 | 2920 | struct mem_cgroup *memcg = NULL; |
2922 | 2921 | unsigned int nr_pages = 1; |
2923 | 2922 | struct page_cgroup *pc; |
2923 | + bool anon; | |
2924 | 2924 | |
2925 | 2925 | if (mem_cgroup_disabled()) |
2926 | 2926 | return NULL; |
2927 | 2927 | |
... | ... | @@ -2946,8 +2946,12 @@ |
2946 | 2946 | if (!PageCgroupUsed(pc)) |
2947 | 2947 | goto unlock_out; |
2948 | 2948 | |
2949 | + anon = PageAnon(page); | |
2950 | + | |
2949 | 2951 | switch (ctype) { |
2950 | 2952 | case MEM_CGROUP_CHARGE_TYPE_MAPPED: |
2953 | + anon = true; | |
2954 | + /* fallthrough */ | |
2951 | 2955 | case MEM_CGROUP_CHARGE_TYPE_DROP: |
2952 | 2956 | /* See mem_cgroup_prepare_migration() */ |
2953 | 2957 | if (page_mapped(page) || PageCgroupMigration(pc)) |
... | ... | @@ -2964,7 +2968,7 @@ |
2964 | 2968 | break; |
2965 | 2969 | } |
2966 | 2970 | |
2967 | - mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -nr_pages); | |
2971 | + mem_cgroup_charge_statistics(memcg, anon, -nr_pages); | |
2968 | 2972 | |
2969 | 2973 | ClearPageCgroupUsed(pc); |
2970 | 2974 | /* |
... | ... | @@ -3271,6 +3275,7 @@ |
3271 | 3275 | { |
3272 | 3276 | struct page *used, *unused; |
3273 | 3277 | struct page_cgroup *pc; |
3278 | + bool anon; | |
3274 | 3279 | |
3275 | 3280 | if (!memcg) |
3276 | 3281 | return; |
3277 | 3282 | |
... | ... | @@ -3292,9 +3297,11 @@ |
3292 | 3297 | lock_page_cgroup(pc); |
3293 | 3298 | ClearPageCgroupMigration(pc); |
3294 | 3299 | unlock_page_cgroup(pc); |
3300 | + anon = PageAnon(used); | |
3301 | + __mem_cgroup_uncharge_common(unused, | |
3302 | + anon ? MEM_CGROUP_CHARGE_TYPE_MAPPED | |
3303 | + : MEM_CGROUP_CHARGE_TYPE_CACHE); | |
3295 | 3304 | |
3296 | - __mem_cgroup_uncharge_common(unused, MEM_CGROUP_CHARGE_TYPE_FORCE); | |
3297 | - | |
3298 | 3305 | /* |
3299 | 3306 | * If a page is a file cache, radix-tree replacement is very atomic |
3300 | 3307 | * and we can skip this check. When it was an Anon page, its mapcount |
... | ... | @@ -3303,7 +3310,7 @@ |
3303 | 3310 | * and USED bit check in mem_cgroup_uncharge_page() will do enough |
3304 | 3311 | * check. (see prepare_charge() also) |
3305 | 3312 | */ |
3306 | - if (PageAnon(used)) | |
3313 | + if (anon) | |
3307 | 3314 | mem_cgroup_uncharge_page(used); |
3308 | 3315 | /* |
3309 | 3316 | * At migration, we may charge account against cgroup which has no |
... | ... | @@ -3333,7 +3340,7 @@ |
3333 | 3340 | /* fix accounting on old pages */ |
3334 | 3341 | lock_page_cgroup(pc); |
3335 | 3342 | memcg = pc->mem_cgroup; |
3336 | - mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1); | |
3343 | + mem_cgroup_charge_statistics(memcg, false, -1); | |
3337 | 3344 | ClearPageCgroupUsed(pc); |
3338 | 3345 | unlock_page_cgroup(pc); |
3339 | 3346 |