Skip to content

Commit b382bbb

Browse files
rgushchinAvenger-285714
authored andcommitted
mm: kmem: scoped objcg protection
mainline inlcusion from mainline-v6.7-rc1 category: performance commit e86828e upstream. 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/20231019225346.1822282-5-roman.gushchin@linux.dev Signed-off-by: Roman Gushchin (Cruise) <roman.gushchin@linux.dev> Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org> Acked-by: Shakeel Butt <shakeelb@google.com> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Cc: David Rientjes <rientjes@google.com> Cc: Dennis Zhou <dennis@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: Muchun Song <muchun.song@linux.dev> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> (cherry picked from commit e86828e) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent 14bd33e commit b382bbb

4 files changed

Lines changed: 66 additions & 9 deletions

File tree

include/linux/memcontrol.h

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

1773+
/*
1774+
* The returned objcg pointer is safe to use without additional
1775+
* protection within a scope. The scope is defined either by
1776+
* the current task (similar to the "current" global variable)
1777+
* or by set_active_memcg() pair.
1778+
* Please, use obj_cgroup_get() to get a reference if the pointer
1779+
* needs to be used outside of the local scope.
1780+
*/
1781+
struct obj_cgroup *current_obj_cgroup(void);
17731782
struct obj_cgroup *get_obj_cgroup_from_current(void);
17741783
struct obj_cgroup *get_obj_cgroup_from_folio(struct folio *folio);
17751784

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
@@ -3092,6 +3092,49 @@ __always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)
30923092
return objcg;
30933093
}
30943094

3095+
__always_inline struct obj_cgroup *current_obj_cgroup(void)
3096+
{
3097+
struct mem_cgroup *memcg;
3098+
struct obj_cgroup *objcg;
3099+
3100+
if (in_task()) {
3101+
memcg = current->active_memcg;
3102+
if (unlikely(memcg))
3103+
goto from_memcg;
3104+
3105+
objcg = READ_ONCE(current->objcg);
3106+
if (unlikely((unsigned long)objcg & CURRENT_OBJCG_UPDATE_FLAG))
3107+
objcg = current_objcg_update();
3108+
/*
3109+
* Objcg reference is kept by the task, so it's safe
3110+
* to use the objcg by the current task.
3111+
*/
3112+
return objcg;
3113+
}
3114+
3115+
memcg = this_cpu_read(int_active_memcg);
3116+
if (unlikely(memcg))
3117+
goto from_memcg;
3118+
3119+
return NULL;
3120+
3121+
from_memcg:
3122+
for (; !mem_cgroup_is_root(memcg); memcg = parent_mem_cgroup(memcg)) {
3123+
/*
3124+
* Memcg pointer is protected by scope (see set_active_memcg())
3125+
* and is pinning the corresponding objcg, so objcg can't go
3126+
* away and can be used within the scope without any additional
3127+
* protection.
3128+
*/
3129+
objcg = rcu_dereference_check(memcg->objcg, 1);
3130+
if (likely(objcg))
3131+
break;
3132+
objcg = NULL;
3133+
}
3134+
3135+
return objcg;
3136+
}
3137+
30953138
struct obj_cgroup *get_obj_cgroup_from_folio(struct folio *folio)
30963139
{
30973140
struct obj_cgroup *objcg;
@@ -3186,15 +3229,15 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)
31863229
struct obj_cgroup *objcg;
31873230
int ret = 0;
31883231

3189-
objcg = get_obj_cgroup_from_current();
3232+
objcg = current_obj_cgroup();
31903233
if (objcg) {
31913234
ret = obj_cgroup_charge_pages(objcg, gfp, 1 << order);
31923235
if (!ret) {
3236+
obj_cgroup_get(objcg);
31933237
page->memcg_data = (unsigned long)objcg |
31943238
MEMCG_DATA_KMEM;
31953239
return 0;
31963240
}
3197-
obj_cgroup_put(objcg);
31983241
}
31993242
return ret;
32003243
}

mm/slab.h

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

495-
objcg = get_obj_cgroup_from_current();
495+
/*
496+
* The obtained objcg pointer is safe to use within the current scope,
497+
* defined by current task or set_active_memcg() pair.
498+
* obj_cgroup_get() is used to get a permanent reference.
499+
*/
500+
objcg = current_obj_cgroup();
496501
if (!objcg)
497502
return true;
498503

@@ -505,17 +510,14 @@ static inline bool memcg_slab_pre_alloc_hook(struct kmem_cache *s,
505510
css_put(&memcg->css);
506511

507512
if (ret)
508-
goto out;
513+
return false;
509514
}
510515

511516
if (obj_cgroup_charge(objcg, flags, objects * obj_full_size(s)))
512-
goto out;
517+
return false;
513518

514519
*objcgp = objcg;
515520
return true;
516-
out:
517-
obj_cgroup_put(objcg);
518-
return false;
519521
}
520522

521523
static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
@@ -550,7 +552,6 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
550552
obj_cgroup_uncharge(objcg, obj_full_size(s));
551553
}
552554
}
553-
obj_cgroup_put(objcg);
554555
}
555556

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

0 commit comments

Comments
 (0)