Skip to content

Commit e86828e

Browse files
rgushchinakpm00
authored andcommitted
mm: kmem: scoped objcg protection
Switch to a scope-based protection of the objcg pointer on slab/kmem allocation paths. Instead of using the get_() semantics in the pre-allocation hook and put the reference afterwards, let's rely on the fact that objcg is pinned by the scope. It's possible because: 1) if the objcg is received from the current task struct, the task is keeping a reference to the objcg. 2) if the objcg is received from an active memcg (remote charging), the memcg is pinned by the scope and has a reference to the corresponding objcg. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Roman Gushchin (Cruise) <[email protected]> Tested-by: Naresh Kamboju <[email protected]> Acked-by: Shakeel Butt <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: David Rientjes <[email protected]> Cc: Dennis Zhou <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Muchun Song <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 675d6c9 commit e86828e

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

include/linux/memcontrol.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,15 @@ bool mem_cgroup_kmem_disabled(void);
17961796
int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order);
17971797
void __memcg_kmem_uncharge_page(struct page *page, int order);
17981798

1799+
/*
1800+
* The returned objcg pointer is safe to use without additional
1801+
* protection within a scope. The scope is defined either by
1802+
* the current task (similar to the "current" global variable)
1803+
* or by set_active_memcg() pair.
1804+
* Please, use obj_cgroup_get() to get a reference if the pointer
1805+
* needs to be used outside of the local scope.
1806+
*/
1807+
struct obj_cgroup *current_obj_cgroup(void);
17991808
struct obj_cgroup *get_obj_cgroup_from_current(void);
18001809
struct obj_cgroup *get_obj_cgroup_from_folio(struct folio *folio);
18011810

include/linux/sched/mm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ DECLARE_PER_CPU(struct mem_cgroup *, int_active_memcg);
403403
* __GFP_ACCOUNT allocations till the end of the scope will be charged to the
404404
* given memcg.
405405
*
406+
* Please, make sure that caller has a reference to the passed memcg structure,
407+
* so its lifetime is guaranteed to exceed the scope between two
408+
* set_active_memcg() calls.
409+
*
406410
* NOTE: This function can nest. Users must save the return value and
407411
* reset the previous value after their own charging scope is over.
408412
*/

mm/memcontrol.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3170,6 +3170,49 @@ __always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)
31703170
return objcg;
31713171
}
31723172

3173+
__always_inline struct obj_cgroup *current_obj_cgroup(void)
3174+
{
3175+
struct mem_cgroup *memcg;
3176+
struct obj_cgroup *objcg;
3177+
3178+
if (in_task()) {
3179+
memcg = current->active_memcg;
3180+
if (unlikely(memcg))
3181+
goto from_memcg;
3182+
3183+
objcg = READ_ONCE(current->objcg);
3184+
if (unlikely((unsigned long)objcg & CURRENT_OBJCG_UPDATE_FLAG))
3185+
objcg = current_objcg_update();
3186+
/*
3187+
* Objcg reference is kept by the task, so it's safe
3188+
* to use the objcg by the current task.
3189+
*/
3190+
return objcg;
3191+
}
3192+
3193+
memcg = this_cpu_read(int_active_memcg);
3194+
if (unlikely(memcg))
3195+
goto from_memcg;
3196+
3197+
return NULL;
3198+
3199+
from_memcg:
3200+
for (; !mem_cgroup_is_root(memcg); memcg = parent_mem_cgroup(memcg)) {
3201+
/*
3202+
* Memcg pointer is protected by scope (see set_active_memcg())
3203+
* and is pinning the corresponding objcg, so objcg can't go
3204+
* away and can be used within the scope without any additional
3205+
* protection.
3206+
*/
3207+
objcg = rcu_dereference_check(memcg->objcg, 1);
3208+
if (likely(objcg))
3209+
break;
3210+
objcg = NULL;
3211+
}
3212+
3213+
return objcg;
3214+
}
3215+
31733216
struct obj_cgroup *get_obj_cgroup_from_folio(struct folio *folio)
31743217
{
31753218
struct obj_cgroup *objcg;
@@ -3264,15 +3307,15 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)
32643307
struct obj_cgroup *objcg;
32653308
int ret = 0;
32663309

3267-
objcg = get_obj_cgroup_from_current();
3310+
objcg = current_obj_cgroup();
32683311
if (objcg) {
32693312
ret = obj_cgroup_charge_pages(objcg, gfp, 1 << order);
32703313
if (!ret) {
3314+
obj_cgroup_get(objcg);
32713315
page->memcg_data = (unsigned long)objcg |
32723316
MEMCG_DATA_KMEM;
32733317
return 0;
32743318
}
3275-
obj_cgroup_put(objcg);
32763319
}
32773320
return ret;
32783321
}

mm/slab.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,12 @@ static inline bool memcg_slab_pre_alloc_hook(struct kmem_cache *s,
484484
if (!(flags & __GFP_ACCOUNT) && !(s->flags & SLAB_ACCOUNT))
485485
return true;
486486

487-
objcg = get_obj_cgroup_from_current();
487+
/*
488+
* The obtained objcg pointer is safe to use within the current scope,
489+
* defined by current task or set_active_memcg() pair.
490+
* obj_cgroup_get() is used to get a permanent reference.
491+
*/
492+
objcg = current_obj_cgroup();
488493
if (!objcg)
489494
return true;
490495

@@ -497,17 +502,14 @@ static inline bool memcg_slab_pre_alloc_hook(struct kmem_cache *s,
497502
css_put(&memcg->css);
498503

499504
if (ret)
500-
goto out;
505+
return false;
501506
}
502507

503508
if (obj_cgroup_charge(objcg, flags, objects * obj_full_size(s)))
504-
goto out;
509+
return false;
505510

506511
*objcgp = objcg;
507512
return true;
508-
out:
509-
obj_cgroup_put(objcg);
510-
return false;
511513
}
512514

513515
static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
@@ -542,7 +544,6 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
542544
obj_cgroup_uncharge(objcg, obj_full_size(s));
543545
}
544546
}
545-
obj_cgroup_put(objcg);
546547
}
547548

548549
static inline void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,

0 commit comments

Comments
 (0)