Skip to content

Commit 4d96ba3

Browse files
rgushchintorvalds
authored andcommitted
mm: memcg/slab: stop setting page->mem_cgroup pointer for slab pages
Every slab page charged to a non-root memory cgroup has a pointer to the memory cgroup and holds a reference to it, which protects a non-empty memory cgroup from being released. At the same time the page has a pointer to the corresponding kmem_cache, and also hold a reference to the kmem_cache. And kmem_cache by itself holds a reference to the cgroup. So there is clearly some redundancy, which allows to stop setting the page->mem_cgroup pointer and rely on getting memcg pointer indirectly via kmem_cache. Further it will allow to change this pointer easier, without a need to go over all charged pages. So let's stop setting page->mem_cgroup pointer for slab pages, and stop using the css refcounter directly for protecting the memory cgroup from going away. Instead rely on kmem_cache as an intermediate object. Make sure that vmstats and shrinker lists are working as previously, as well as /proc/kpagecgroup interface. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Roman Gushchin <[email protected]> Acked-by: Vladimir Davydov <[email protected]> Reviewed-by: Shakeel Butt <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Waiman Long <[email protected]> Cc: David Rientjes <[email protected]> Cc: Joonsoo Kim <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Andrei Vagin <[email protected]> Cc: Qian Cai <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent f0a3a24 commit 4d96ba3

File tree

3 files changed

+70
-19
lines changed

3 files changed

+70
-19
lines changed

mm/list_lru.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/slab.h>
1313
#include <linux/mutex.h>
1414
#include <linux/memcontrol.h>
15+
#include "slab.h"
1516

1617
#ifdef CONFIG_MEMCG_KMEM
1718
static LIST_HEAD(list_lrus);
@@ -63,7 +64,7 @@ static __always_inline struct mem_cgroup *mem_cgroup_from_kmem(void *ptr)
6364
if (!memcg_kmem_enabled())
6465
return NULL;
6566
page = virt_to_head_page(ptr);
66-
return page->mem_cgroup;
67+
return memcg_from_slab_page(page);
6768
}
6869

6970
static inline struct list_lru_one *

mm/memcontrol.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,10 @@ ino_t page_cgroup_ino(struct page *page)
486486
unsigned long ino = 0;
487487

488488
rcu_read_lock();
489-
memcg = READ_ONCE(page->mem_cgroup);
489+
if (PageHead(page) && PageSlab(page))
490+
memcg = memcg_from_slab_page(page);
491+
else
492+
memcg = READ_ONCE(page->mem_cgroup);
490493
while (memcg && !(memcg->css.flags & CSS_ONLINE))
491494
memcg = parent_mem_cgroup(memcg);
492495
if (memcg)
@@ -2802,9 +2805,6 @@ int __memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,
28022805
cancel_charge(memcg, nr_pages);
28032806
return -ENOMEM;
28042807
}
2805-
2806-
page->mem_cgroup = memcg;
2807-
28082808
return 0;
28092809
}
28102810

@@ -2827,8 +2827,10 @@ int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
28272827
memcg = get_mem_cgroup_from_current();
28282828
if (!mem_cgroup_is_root(memcg)) {
28292829
ret = __memcg_kmem_charge_memcg(page, gfp, order, memcg);
2830-
if (!ret)
2830+
if (!ret) {
2831+
page->mem_cgroup = memcg;
28312832
__SetPageKmemcg(page);
2833+
}
28322834
}
28332835
css_put(&memcg->css);
28342836
return ret;

mm/slab.h

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -255,30 +255,67 @@ static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
255255
return s->memcg_params.root_cache;
256256
}
257257

258+
/*
259+
* Expects a pointer to a slab page. Please note, that PageSlab() check
260+
* isn't sufficient, as it returns true also for tail compound slab pages,
261+
* which do not have slab_cache pointer set.
262+
* So this function assumes that the page can pass PageHead() and PageSlab()
263+
* checks.
264+
*/
265+
static inline struct mem_cgroup *memcg_from_slab_page(struct page *page)
266+
{
267+
struct kmem_cache *s;
268+
269+
s = READ_ONCE(page->slab_cache);
270+
if (s && !is_root_cache(s))
271+
return s->memcg_params.memcg;
272+
273+
return NULL;
274+
}
275+
276+
/*
277+
* Charge the slab page belonging to the non-root kmem_cache.
278+
* Can be called for non-root kmem_caches only.
279+
*/
258280
static __always_inline int memcg_charge_slab(struct page *page,
259281
gfp_t gfp, int order,
260282
struct kmem_cache *s)
261283
{
284+
struct mem_cgroup *memcg;
285+
struct lruvec *lruvec;
262286
int ret;
263287

264-
if (is_root_cache(s))
265-
return 0;
266-
267-
ret = memcg_kmem_charge_memcg(page, gfp, order, s->memcg_params.memcg);
288+
memcg = s->memcg_params.memcg;
289+
ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
268290
if (ret)
269291
return ret;
270292

293+
lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
294+
mod_lruvec_state(lruvec, cache_vmstat_idx(s), 1 << order);
295+
296+
/* transer try_charge() page references to kmem_cache */
271297
percpu_ref_get_many(&s->memcg_params.refcnt, 1 << order);
298+
css_put_many(&memcg->css, 1 << order);
272299

273300
return 0;
274301
}
275302

303+
/*
304+
* Uncharge a slab page belonging to a non-root kmem_cache.
305+
* Can be called for non-root kmem_caches only.
306+
*/
276307
static __always_inline void memcg_uncharge_slab(struct page *page, int order,
277308
struct kmem_cache *s)
278309
{
279-
if (!is_root_cache(s))
280-
percpu_ref_put_many(&s->memcg_params.refcnt, 1 << order);
281-
memcg_kmem_uncharge(page, order);
310+
struct mem_cgroup *memcg;
311+
struct lruvec *lruvec;
312+
313+
memcg = s->memcg_params.memcg;
314+
lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
315+
mod_lruvec_state(lruvec, cache_vmstat_idx(s), -(1 << order));
316+
memcg_kmem_uncharge_memcg(page, order, memcg);
317+
318+
percpu_ref_put_many(&s->memcg_params.refcnt, 1 << order);
282319
}
283320

284321
extern void slab_init_memcg_params(struct kmem_cache *);
@@ -314,6 +351,11 @@ static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
314351
return s;
315352
}
316353

354+
static inline struct mem_cgroup *memcg_from_slab_page(struct page *page)
355+
{
356+
return NULL;
357+
}
358+
317359
static inline int memcg_charge_slab(struct page *page, gfp_t gfp, int order,
318360
struct kmem_cache *s)
319361
{
@@ -351,18 +393,24 @@ static __always_inline int charge_slab_page(struct page *page,
351393
gfp_t gfp, int order,
352394
struct kmem_cache *s)
353395
{
354-
int ret = memcg_charge_slab(page, gfp, order, s);
355-
356-
if (!ret)
357-
mod_lruvec_page_state(page, cache_vmstat_idx(s), 1 << order);
396+
if (is_root_cache(s)) {
397+
mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
398+
1 << order);
399+
return 0;
400+
}
358401

359-
return ret;
402+
return memcg_charge_slab(page, gfp, order, s);
360403
}
361404

362405
static __always_inline void uncharge_slab_page(struct page *page, int order,
363406
struct kmem_cache *s)
364407
{
365-
mod_lruvec_page_state(page, cache_vmstat_idx(s), -(1 << order));
408+
if (is_root_cache(s)) {
409+
mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
410+
-(1 << order));
411+
return;
412+
}
413+
366414
memcg_uncharge_slab(page, order, s);
367415
}
368416

0 commit comments

Comments
 (0)