Skip to content

Commit be5d0a7

Browse files
hnaztorvalds
authored andcommitted
mm: memcontrol: switch to native NR_ANON_MAPPED counter
Memcg maintains a private MEMCG_RSS counter. This divergence from the generic VM accounting means unnecessary code overhead, and creates a dependency for memcg that page->mapping is set up at the time of charging, so that page types can be told apart. Convert the generic accounting sites to mod_lruvec_page_state and friends to maintain the per-cgroup vmstat counter of NR_ANON_MAPPED. We use lock_page_memcg() to stabilize page->mem_cgroup during rmap changes, the same way we do for NR_FILE_MAPPED. With the previous patch removing MEMCG_CACHE and the private NR_SHMEM counter, this patch finally eliminates the need to have page->mapping set up at charge time. However, we need to have page->mem_cgroup set up by the time rmap runs and does the accounting, so switch the commit and the rmap callbacks around. v2: fix temporary accounting bug by switching rmap<->commit (Joonsoo) Signed-off-by: Johannes Weiner <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Cc: Alex Shi <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Joonsoo Kim <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Balbir Singh <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent 0d1c207 commit be5d0a7

File tree

10 files changed

+51
-50
lines changed

10 files changed

+51
-50
lines changed

include/linux/memcontrol.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ struct kmem_cache;
2929

3030
/* Cgroup-specific page state, on top of universal node page state */
3131
enum memcg_stat_item {
32-
MEMCG_RSS = NR_VM_NODE_STAT_ITEMS,
33-
MEMCG_RSS_HUGE,
32+
MEMCG_RSS_HUGE = NR_VM_NODE_STAT_ITEMS,
3433
MEMCG_SWAP,
3534
MEMCG_SOCK,
3635
/* XXX: why are these zone and not node counters? */

kernel/events/uprobes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
188188

189189
if (new_page) {
190190
get_page(new_page);
191-
page_add_new_anon_rmap(new_page, vma, addr, false);
192191
mem_cgroup_commit_charge(new_page, memcg, false);
192+
page_add_new_anon_rmap(new_page, vma, addr, false);
193193
lru_cache_add_active_or_unevictable(new_page, vma);
194194
} else
195195
/* no new page, just dec_mm_counter for old_page */

mm/huge_memory.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,8 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf,
640640

641641
entry = mk_huge_pmd(page, vma->vm_page_prot);
642642
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
643-
page_add_new_anon_rmap(page, vma, haddr, true);
644643
mem_cgroup_commit_charge(page, memcg, false);
644+
page_add_new_anon_rmap(page, vma, haddr, true);
645645
lru_cache_add_active_or_unevictable(page, vma);
646646
pgtable_trans_huge_deposit(vma->vm_mm, vmf->pmd, pgtable);
647647
set_pmd_at(vma->vm_mm, haddr, vmf->pmd, entry);

mm/khugepaged.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,8 +1175,8 @@ static void collapse_huge_page(struct mm_struct *mm,
11751175

11761176
spin_lock(pmd_ptl);
11771177
BUG_ON(!pmd_none(*pmd));
1178-
page_add_new_anon_rmap(new_page, vma, address, true);
11791178
mem_cgroup_commit_charge(new_page, memcg, false);
1179+
page_add_new_anon_rmap(new_page, vma, address, true);
11801180
count_memcg_events(memcg, THP_COLLAPSE_ALLOC, 1);
11811181
lru_cache_add_active_or_unevictable(new_page, vma);
11821182
pgtable_trans_huge_deposit(mm, pmd, pgtable);

mm/memcontrol.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -836,13 +836,6 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
836836
struct page *page,
837837
int nr_pages)
838838
{
839-
/*
840-
* Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
841-
* counted as CACHE even if it's on ANON LRU.
842-
*/
843-
if (PageAnon(page))
844-
__mod_memcg_state(memcg, MEMCG_RSS, nr_pages);
845-
846839
if (abs(nr_pages) > 1) {
847840
VM_BUG_ON_PAGE(!PageTransHuge(page), page);
848841
__mod_memcg_state(memcg, MEMCG_RSS_HUGE, nr_pages);
@@ -1384,7 +1377,7 @@ static char *memory_stat_format(struct mem_cgroup *memcg)
13841377
*/
13851378

13861379
seq_buf_printf(&s, "anon %llu\n",
1387-
(u64)memcg_page_state(memcg, MEMCG_RSS) *
1380+
(u64)memcg_page_state(memcg, NR_ANON_MAPPED) *
13881381
PAGE_SIZE);
13891382
seq_buf_printf(&s, "file %llu\n",
13901383
(u64)memcg_page_state(memcg, NR_FILE_PAGES) *
@@ -3353,7 +3346,7 @@ static unsigned long mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
33533346

33543347
if (mem_cgroup_is_root(memcg)) {
33553348
val = memcg_page_state(memcg, NR_FILE_PAGES) +
3356-
memcg_page_state(memcg, MEMCG_RSS);
3349+
memcg_page_state(memcg, NR_ANON_MAPPED);
33573350
if (swap)
33583351
val += memcg_page_state(memcg, MEMCG_SWAP);
33593352
} else {
@@ -3824,7 +3817,7 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v)
38243817

38253818
static const unsigned int memcg1_stats[] = {
38263819
NR_FILE_PAGES,
3827-
MEMCG_RSS,
3820+
NR_ANON_MAPPED,
38283821
MEMCG_RSS_HUGE,
38293822
NR_SHMEM,
38303823
NR_FILE_MAPPED,
@@ -5455,7 +5448,12 @@ static int mem_cgroup_move_account(struct page *page,
54555448

54565449
lock_page_memcg(page);
54575450

5458-
if (!PageAnon(page)) {
5451+
if (PageAnon(page)) {
5452+
if (page_mapped(page)) {
5453+
__mod_lruvec_state(from_vec, NR_ANON_MAPPED, -nr_pages);
5454+
__mod_lruvec_state(to_vec, NR_ANON_MAPPED, nr_pages);
5455+
}
5456+
} else {
54595457
__mod_lruvec_state(from_vec, NR_FILE_PAGES, -nr_pages);
54605458
__mod_lruvec_state(to_vec, NR_FILE_PAGES, nr_pages);
54615459

@@ -6589,7 +6587,6 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
65896587
{
65906588
unsigned int nr_pages = hpage_nr_pages(page);
65916589

6592-
VM_BUG_ON_PAGE(!page->mapping, page);
65936590
VM_BUG_ON_PAGE(PageLRU(page) && !lrucare, page);
65946591

65956592
if (mem_cgroup_disabled())
@@ -6662,8 +6659,6 @@ int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask,
66626659
struct mem_cgroup *memcg;
66636660
int ret;
66646661

6665-
VM_BUG_ON_PAGE(!page->mapping, page);
6666-
66676662
ret = mem_cgroup_try_charge(page, mm, gfp_mask, &memcg);
66686663
if (ret)
66696664
return ret;
@@ -6675,7 +6670,6 @@ struct uncharge_gather {
66756670
struct mem_cgroup *memcg;
66766671
unsigned long nr_pages;
66776672
unsigned long pgpgout;
6678-
unsigned long nr_anon;
66796673
unsigned long nr_kmem;
66806674
unsigned long nr_huge;
66816675
struct page *dummy_page;
@@ -6700,7 +6694,6 @@ static void uncharge_batch(const struct uncharge_gather *ug)
67006694
}
67016695

67026696
local_irq_save(flags);
6703-
__mod_memcg_state(ug->memcg, MEMCG_RSS, -ug->nr_anon);
67046697
__mod_memcg_state(ug->memcg, MEMCG_RSS_HUGE, -ug->nr_huge);
67056698
__count_memcg_events(ug->memcg, PGPGOUT, ug->pgpgout);
67066699
__this_cpu_add(ug->memcg->vmstats_percpu->nr_page_events, ug->nr_pages);
@@ -6740,8 +6733,6 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
67406733
if (!PageKmemcg(page)) {
67416734
if (PageTransHuge(page))
67426735
ug->nr_huge += nr_pages;
6743-
if (PageAnon(page))
6744-
ug->nr_anon += nr_pages;
67456736
ug->pgpgout++;
67466737
} else {
67476738
ug->nr_kmem += nr_pages;

mm/memory.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,8 +2710,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
27102710
* thread doing COW.
27112711
*/
27122712
ptep_clear_flush_notify(vma, vmf->address, vmf->pte);
2713-
page_add_new_anon_rmap(new_page, vma, vmf->address, false);
27142713
mem_cgroup_commit_charge(new_page, memcg, false);
2714+
page_add_new_anon_rmap(new_page, vma, vmf->address, false);
27152715
lru_cache_add_active_or_unevictable(new_page, vma);
27162716
/*
27172717
* We call the notify macro here because, when using secondary
@@ -3243,12 +3243,12 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
32433243

32443244
/* ksm created a completely new copy */
32453245
if (unlikely(page != swapcache && swapcache)) {
3246-
page_add_new_anon_rmap(page, vma, vmf->address, false);
32473246
mem_cgroup_commit_charge(page, memcg, false);
3247+
page_add_new_anon_rmap(page, vma, vmf->address, false);
32483248
lru_cache_add_active_or_unevictable(page, vma);
32493249
} else {
3250-
do_page_add_anon_rmap(page, vma, vmf->address, exclusive);
32513250
mem_cgroup_commit_charge(page, memcg, true);
3251+
do_page_add_anon_rmap(page, vma, vmf->address, exclusive);
32523252
activate_page(page);
32533253
}
32543254

@@ -3390,8 +3390,8 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
33903390
}
33913391

33923392
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
3393-
page_add_new_anon_rmap(page, vma, vmf->address, false);
33943393
mem_cgroup_commit_charge(page, memcg, false);
3394+
page_add_new_anon_rmap(page, vma, vmf->address, false);
33953395
lru_cache_add_active_or_unevictable(page, vma);
33963396
setpte:
33973397
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
@@ -3652,8 +3652,8 @@ vm_fault_t alloc_set_pte(struct vm_fault *vmf, struct mem_cgroup *memcg,
36523652
/* copy-on-write page */
36533653
if (write && !(vma->vm_flags & VM_SHARED)) {
36543654
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
3655-
page_add_new_anon_rmap(page, vma, vmf->address, false);
36563655
mem_cgroup_commit_charge(page, memcg, false);
3656+
page_add_new_anon_rmap(page, vma, vmf->address, false);
36573657
lru_cache_add_active_or_unevictable(page, vma);
36583658
} else {
36593659
inc_mm_counter_fast(vma->vm_mm, mm_counter_file(page));

mm/migrate.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2832,8 +2832,8 @@ static void migrate_vma_insert_page(struct migrate_vma *migrate,
28322832
goto unlock_abort;
28332833

28342834
inc_mm_counter(mm, MM_ANONPAGES);
2835-
page_add_new_anon_rmap(page, vma, addr, false);
28362835
mem_cgroup_commit_charge(page, memcg, false);
2836+
page_add_new_anon_rmap(page, vma, addr, false);
28372837
if (!is_zone_device_page(page))
28382838
lru_cache_add_active_or_unevictable(page, vma);
28392839
get_page(page);

mm/rmap.c

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,11 @@ void do_page_add_anon_rmap(struct page *page,
11141114
bool compound = flags & RMAP_COMPOUND;
11151115
bool first;
11161116

1117+
if (unlikely(PageKsm(page)))
1118+
lock_page_memcg(page);
1119+
else
1120+
VM_BUG_ON_PAGE(!PageLocked(page), page);
1121+
11171122
if (compound) {
11181123
atomic_t *mapcount;
11191124
VM_BUG_ON_PAGE(!PageLocked(page), page);
@@ -1134,12 +1139,13 @@ void do_page_add_anon_rmap(struct page *page,
11341139
*/
11351140
if (compound)
11361141
__inc_node_page_state(page, NR_ANON_THPS);
1137-
__mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
1142+
__mod_lruvec_page_state(page, NR_ANON_MAPPED, nr);
11381143
}
1139-
if (unlikely(PageKsm(page)))
1140-
return;
11411144

1142-
VM_BUG_ON_PAGE(!PageLocked(page), page);
1145+
if (unlikely(PageKsm(page))) {
1146+
unlock_page_memcg(page);
1147+
return;
1148+
}
11431149

11441150
/* address might be in next vma when migration races vma_adjust */
11451151
if (first)
@@ -1181,7 +1187,7 @@ void page_add_new_anon_rmap(struct page *page,
11811187
/* increment count (starts at -1) */
11821188
atomic_set(&page->_mapcount, 0);
11831189
}
1184-
__mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
1190+
__mod_lruvec_page_state(page, NR_ANON_MAPPED, nr);
11851191
__page_set_anon_rmap(page, vma, address, 1);
11861192
}
11871193

@@ -1230,13 +1236,12 @@ static void page_remove_file_rmap(struct page *page, bool compound)
12301236
int i, nr = 1;
12311237

12321238
VM_BUG_ON_PAGE(compound && !PageHead(page), page);
1233-
lock_page_memcg(page);
12341239

12351240
/* Hugepages are not counted in NR_FILE_MAPPED for now. */
12361241
if (unlikely(PageHuge(page))) {
12371242
/* hugetlb pages are always mapped with pmds */
12381243
atomic_dec(compound_mapcount_ptr(page));
1239-
goto out;
1244+
return;
12401245
}
12411246

12421247
/* page still mapped by someone else? */
@@ -1246,14 +1251,14 @@ static void page_remove_file_rmap(struct page *page, bool compound)
12461251
nr++;
12471252
}
12481253
if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
1249-
goto out;
1254+
return;
12501255
if (PageSwapBacked(page))
12511256
__dec_node_page_state(page, NR_SHMEM_PMDMAPPED);
12521257
else
12531258
__dec_node_page_state(page, NR_FILE_PMDMAPPED);
12541259
} else {
12551260
if (!atomic_add_negative(-1, &page->_mapcount))
1256-
goto out;
1261+
return;
12571262
}
12581263

12591264
/*
@@ -1265,8 +1270,6 @@ static void page_remove_file_rmap(struct page *page, bool compound)
12651270

12661271
if (unlikely(PageMlocked(page)))
12671272
clear_page_mlock(page);
1268-
out:
1269-
unlock_page_memcg(page);
12701273
}
12711274

12721275
static void page_remove_anon_compound_rmap(struct page *page)
@@ -1310,7 +1313,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
13101313
clear_page_mlock(page);
13111314

13121315
if (nr)
1313-
__mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, -nr);
1316+
__mod_lruvec_page_state(page, NR_ANON_MAPPED, -nr);
13141317
}
13151318

13161319
/**
@@ -1322,22 +1325,28 @@ static void page_remove_anon_compound_rmap(struct page *page)
13221325
*/
13231326
void page_remove_rmap(struct page *page, bool compound)
13241327
{
1325-
if (!PageAnon(page))
1326-
return page_remove_file_rmap(page, compound);
1328+
lock_page_memcg(page);
13271329

1328-
if (compound)
1329-
return page_remove_anon_compound_rmap(page);
1330+
if (!PageAnon(page)) {
1331+
page_remove_file_rmap(page, compound);
1332+
goto out;
1333+
}
1334+
1335+
if (compound) {
1336+
page_remove_anon_compound_rmap(page);
1337+
goto out;
1338+
}
13301339

13311340
/* page still mapped by someone else? */
13321341
if (!atomic_add_negative(-1, &page->_mapcount))
1333-
return;
1342+
goto out;
13341343

13351344
/*
13361345
* We use the irq-unsafe __{inc|mod}_zone_page_stat because
13371346
* these counters are not modified in interrupt context, and
13381347
* pte lock(a spinlock) is held, which implies preemption disabled.
13391348
*/
1340-
__dec_node_page_state(page, NR_ANON_MAPPED);
1349+
__dec_lruvec_page_state(page, NR_ANON_MAPPED);
13411350

13421351
if (unlikely(PageMlocked(page)))
13431352
clear_page_mlock(page);
@@ -1354,6 +1363,8 @@ void page_remove_rmap(struct page *page, bool compound)
13541363
* Leaving it set also helps swapoff to reinstate ptes
13551364
* faster for those pages still in swapcache.
13561365
*/
1366+
out:
1367+
unlock_page_memcg(page);
13571368
}
13581369

13591370
/*

mm/swapfile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,11 +1920,11 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
19201920
set_pte_at(vma->vm_mm, addr, pte,
19211921
pte_mkold(mk_pte(page, vma->vm_page_prot)));
19221922
if (page == swapcache) {
1923-
page_add_anon_rmap(page, vma, addr, false);
19241923
mem_cgroup_commit_charge(page, memcg, true);
1924+
page_add_anon_rmap(page, vma, addr, false);
19251925
} else { /* ksm created a completely new copy */
1926-
page_add_new_anon_rmap(page, vma, addr, false);
19271926
mem_cgroup_commit_charge(page, memcg, false);
1927+
page_add_new_anon_rmap(page, vma, addr, false);
19281928
lru_cache_add_active_or_unevictable(page, vma);
19291929
}
19301930
swap_free(entry);

mm/userfaultfd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm,
123123
goto out_release_uncharge_unlock;
124124

125125
inc_mm_counter(dst_mm, MM_ANONPAGES);
126-
page_add_new_anon_rmap(page, dst_vma, dst_addr, false);
127126
mem_cgroup_commit_charge(page, memcg, false);
127+
page_add_new_anon_rmap(page, dst_vma, dst_addr, false);
128128
lru_cache_add_active_or_unevictable(page, dst_vma);
129129

130130
set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);

0 commit comments

Comments
 (0)