aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorVladimir Davydov <vdavydov@virtuozzo.com>2016-08-08 16:03:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-09 13:14:10 -0400
commitc4159a75b64c0e67caededf4d7372c1b58a5f42a (patch)
treef323cf78d2047591291c67a19741fea8c23a88cd /mm
parent81abf2525827b29839a78fd55ab0699f033c41a5 (diff)
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: 4949148ad433 ("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>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c14
-rw-r--r--mm/page_alloc.c14
2 files changed, 17 insertions, 11 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 66beca1ad92f..e74d7080ec9e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2337,8 +2337,11 @@ int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
2337 return 0; 2337 return 0;
2338 2338
2339 memcg = get_mem_cgroup_from_mm(current->mm); 2339 memcg = get_mem_cgroup_from_mm(current->mm);
2340 if (!mem_cgroup_is_root(memcg)) 2340 if (!mem_cgroup_is_root(memcg)) {
2341 ret = memcg_kmem_charge_memcg(page, gfp, order, memcg); 2341 ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
2342 if (!ret)
2343 __SetPageKmemcg(page);
2344 }
2342 css_put(&memcg->css); 2345 css_put(&memcg->css);
2343 return ret; 2346 return ret;
2344} 2347}
@@ -2365,6 +2368,11 @@ void memcg_kmem_uncharge(struct page *page, int order)
2365 page_counter_uncharge(&memcg->memsw, nr_pages); 2368 page_counter_uncharge(&memcg->memsw, nr_pages);
2366 2369
2367 page->mem_cgroup = NULL; 2370 page->mem_cgroup = NULL;
2371
2372 /* slab pages do not have PageKmemcg flag set */
2373 if (PageKmemcg(page))
2374 __ClearPageKmemcg(page);
2375
2368 css_put_many(&memcg->css, nr_pages); 2376 css_put_many(&memcg->css, nr_pages);
2369} 2377}
2370#endif /* !CONFIG_SLOB */ 2378#endif /* !CONFIG_SLOB */
@@ -5537,8 +5545,10 @@ static void uncharge_list(struct list_head *page_list)
5537 else 5545 else
5538 nr_file += nr_pages; 5546 nr_file += nr_pages;
5539 pgpgout++; 5547 pgpgout++;
5540 } else 5548 } else {
5541 nr_kmem += 1 << compound_order(page); 5549 nr_kmem += 1 << compound_order(page);
5550 __ClearPageKmemcg(page);
5551 }
5542 5552
5543 page->mem_cgroup = NULL; 5553 page->mem_cgroup = NULL;
5544 } while (next != page_list); 5554 } while (next != page_list);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index fb975cec3518..ee744fa3b93d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1008,10 +1008,8 @@ static __always_inline bool free_pages_prepare(struct page *page,
1008 } 1008 }
1009 if (PageMappingFlags(page)) 1009 if (PageMappingFlags(page))
1010 page->mapping = NULL; 1010 page->mapping = NULL;
1011 if (memcg_kmem_enabled() && PageKmemcg(page)) { 1011 if (memcg_kmem_enabled() && PageKmemcg(page))
1012 memcg_kmem_uncharge(page, order); 1012 memcg_kmem_uncharge(page, order);
1013 __ClearPageKmemcg(page);
1014 }
1015 if (check_free) 1013 if (check_free)
1016 bad += free_pages_check(page); 1014 bad += free_pages_check(page);
1017 if (bad) 1015 if (bad)
@@ -3756,12 +3754,10 @@ no_zone:
3756 } 3754 }
3757 3755
3758out: 3756out:
3759 if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page) { 3757 if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page &&
3760 if (unlikely(memcg_kmem_charge(page, gfp_mask, order))) { 3758 unlikely(memcg_kmem_charge(page, gfp_mask, order) != 0)) {
3761 __free_pages(page, order); 3759 __free_pages(page, order);
3762 page = NULL; 3760 page = NULL;
3763 } else
3764 __SetPageKmemcg(page);
3765 } 3761 }
3766 3762
3767 if (kmemcheck_enabled && page) 3763 if (kmemcheck_enabled && page)