Skip to content

Commit c4159a7

Browse files
Vladimir Davydovtorvalds
authored andcommitted
mm: memcontrol: only mark charged pages with PageKmemcg
To distinguish non-slab pages charged to kmemcg we mark them PageKmemcg, which sets page->_mapcount to -512. Currently, we set/clear PageKmemcg in __alloc_pages_nodemask()/free_pages_prepare() for any page allocated with __GFP_ACCOUNT, including those that aren't actually charged to any cgroup, i.e. allocated from the root cgroup context. To avoid overhead in case cgroups are not used, we only do that if memcg_kmem_enabled() is true. The latter is set iff there are kmem-enabled memory cgroups (online or offline). The root cgroup is not considered kmem-enabled. As a result, if a page is allocated with __GFP_ACCOUNT for the root cgroup when there are kmem-enabled memory cgroups and is freed after all kmem-enabled memory cgroups were removed, e.g. # no memory cgroups has been created yet, create one mkdir /sys/fs/cgroup/memory/test # run something allocating pages with __GFP_ACCOUNT, e.g. # a program using pipe dmesg | tail # remove the memory cgroup rmdir /sys/fs/cgroup/memory/test we'll get bad page state bug complaining about page->_mapcount != -1: BUG: Bad page state in process swapper/0 pfn:1fd945c page:ffffea007f651700 count:0 mapcount:-511 mapping: (null) index:0x0 flags: 0x1000000000000000() To avoid that, let's mark with PageKmemcg only those pages that are actually charged to and hence pin a non-root memory cgroup. Fixes: 4949148 ("mm: charge/uncharge kmemcg from generic page allocator paths") Reported-and-tested-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Vladimir Davydov <vdavydov@virtuozzo.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 81abf25 commit c4159a7

File tree

3 files changed

+18
-14
lines changed

3 files changed

+18
-14
lines changed

fs/pipe.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,8 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
144144
struct page *page = buf->page;
145145

146146
if (page_count(page) == 1) {
147-
if (memcg_kmem_enabled()) {
147+
if (memcg_kmem_enabled())
148148
memcg_kmem_uncharge(page, 0);
149-
__ClearPageKmemcg(page);
150-
}
151149
__SetPageLocked(page);
152150
return 0;
153151
}

mm/memcontrol.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,8 +2337,11 @@ int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
23372337
return 0;
23382338

23392339
memcg = get_mem_cgroup_from_mm(current->mm);
2340-
if (!mem_cgroup_is_root(memcg))
2340+
if (!mem_cgroup_is_root(memcg)) {
23412341
ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
2342+
if (!ret)
2343+
__SetPageKmemcg(page);
2344+
}
23422345
css_put(&memcg->css);
23432346
return ret;
23442347
}
@@ -2365,6 +2368,11 @@ void memcg_kmem_uncharge(struct page *page, int order)
23652368
page_counter_uncharge(&memcg->memsw, nr_pages);
23662369

23672370
page->mem_cgroup = NULL;
2371+
2372+
/* slab pages do not have PageKmemcg flag set */
2373+
if (PageKmemcg(page))
2374+
__ClearPageKmemcg(page);
2375+
23682376
css_put_many(&memcg->css, nr_pages);
23692377
}
23702378
#endif /* !CONFIG_SLOB */
@@ -5537,8 +5545,10 @@ static void uncharge_list(struct list_head *page_list)
55375545
else
55385546
nr_file += nr_pages;
55395547
pgpgout++;
5540-
} else
5548+
} else {
55415549
nr_kmem += 1 << compound_order(page);
5550+
__ClearPageKmemcg(page);
5551+
}
55425552

55435553
page->mem_cgroup = NULL;
55445554
} while (next != page_list);

mm/page_alloc.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,10 +1008,8 @@ static __always_inline bool free_pages_prepare(struct page *page,
10081008
}
10091009
if (PageMappingFlags(page))
10101010
page->mapping = NULL;
1011-
if (memcg_kmem_enabled() && PageKmemcg(page)) {
1011+
if (memcg_kmem_enabled() && PageKmemcg(page))
10121012
memcg_kmem_uncharge(page, order);
1013-
__ClearPageKmemcg(page);
1014-
}
10151013
if (check_free)
10161014
bad += free_pages_check(page);
10171015
if (bad)
@@ -3756,12 +3754,10 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
37563754
}
37573755

37583756
out:
3759-
if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page) {
3760-
if (unlikely(memcg_kmem_charge(page, gfp_mask, order))) {
3761-
__free_pages(page, order);
3762-
page = NULL;
3763-
} else
3764-
__SetPageKmemcg(page);
3757+
if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page &&
3758+
unlikely(memcg_kmem_charge(page, gfp_mask, order) != 0)) {
3759+
__free_pages(page, order);
3760+
page = NULL;
37653761
}
37663762

37673763
if (kmemcheck_enabled && page)

0 commit comments

Comments
 (0)