diff options
| author | Vlastimil Babka (SUSE) <vbabka@kernel.org> | 2026-07-27 14:54:06 +0200 |
|---|---|---|
| committer | Vlastimil Babka (SUSE) <vbabka@kernel.org> | 2026-08-04 12:26:55 +0200 |
| commit | d4404b0f5b8b0ff4656d018a0ddfafdbd78879e2 (patch) | |
| tree | 257220f6db46d1fb702beca9fe44941cd15e2912 | |
| parent | 7def2e8549e5186cd4de97ab5ce56f7944d3da59 (diff) | |
mm/slab: stop allocating objcg pointers when unnecessary
Start using the slab_needs_objcg() helper to calculate slabobj_ext size.
Caches that we know to never need objcg pointers (currently
KMALLOC_NORMAL caches) will thus stop wasting memory on them when memory
allocation profiling is enabled.
For things to work properly, we need to also add slab_needs_objcg()
checks to mem_cgroup_from_obj_slab() and memcg_slab_free_hook(), because
when obj_exts array exists for a slab only due to mem_alloc profiling,
we would otherwise attempt to access a non-existing objcg pointer in
that slab.
In slab_obj_ext_[set_]objcg() add debug warnings if called on a slab
where slab_needs_objcg() is false.
Reviewed-by: Hao Li <hao.li@linux.dev>
Link: https://patch.msgid.link/20260727-b4-objext_split-v3-12-c29ef0f1f257@kernel.org
Reviewed-by: Harry Yoo <harry@kernel.org>
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
| -rw-r--r-- | mm/memcontrol.c | 3 | ||||
| -rw-r--r-- | mm/slab.h | 18 | ||||
| -rw-r--r-- | mm/slub.c | 3 |
3 files changed, 21 insertions, 3 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 68e98fb3350e..9971726406d6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2871,6 +2871,9 @@ struct mem_cgroup *mem_cgroup_from_obj_slab(struct slab *slab, void *p) if (!obj_exts) return NULL; + if (!slab_needs_objcg(slab)) + return NULL; + get_slab_obj_exts(obj_exts); obj_ext = slab_obj_ext(slab->slab_cache, slab, obj_exts, p); objcg = slab_obj_ext_objcg(slab, obj_ext); diff --git a/mm/slab.h b/mm/slab.h index 69cd3d9631ff..f76cf2e2ed90 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -615,7 +615,7 @@ static inline size_t cache_obj_ext_size(struct kmem_cache *s) { size_t sz = 0; - if (IS_ENABLED(CONFIG_MEMCG)) + if (cache_needs_objcg(s)) sz += 1; if (slab_obj_ext_has_codetag()) @@ -626,7 +626,15 @@ static inline size_t cache_obj_ext_size(struct kmem_cache *s) static inline size_t slab_obj_ext_size(struct slab *slab) { - return cache_obj_ext_size(slab->slab_cache); + size_t sz = 0; + + if (slab_needs_objcg(slab)) + sz += 1; + + if (slab_obj_ext_has_codetag()) + sz += 1; + + return sizeof(struct slabobj_ext) * sz; } #ifdef CONFIG_SLAB_OBJ_EXT @@ -738,6 +746,8 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts, static inline struct obj_cgroup * slab_obj_ext_objcg(struct slab *slab, struct slabobj_ext *obj_ext) { + VM_WARN_ON_ONCE(!slab_needs_objcg(slab)); + /* if objcg exists, it comes first, so we don't need to do anything */ return obj_ext->_objcg; } @@ -746,6 +756,8 @@ static inline void slab_obj_ext_set_objcg(struct slab *slab, struct slabobj_ext *obj_ext, struct obj_cgroup *objcg) { + VM_WARN_ON_ONCE(!slab_needs_objcg(slab)); + /* if objcg exists, it comes first, so we don't need to do anything */ obj_ext->_objcg = objcg; } @@ -757,7 +769,7 @@ slab_obj_ext_codetag_ref(struct slab *slab, struct slabobj_ext *obj_ext) { VM_WARN_ON_ONCE(!slab_obj_ext_has_codetag()); - if (IS_ENABLED(CONFIG_MEMCG)) + if (slab_needs_objcg(slab)) obj_ext += 1; return &obj_ext->_ctref; diff --git a/mm/slub.c b/mm/slub.c index 331dd9a9b99d..9142f0f4c72f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2513,6 +2513,9 @@ void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p, if (likely(!obj_exts)) return; + if (!slab_needs_objcg(slab)) + return; + get_slab_obj_exts(obj_exts); __memcg_slab_free_hook(s, slab, p, objects, obj_exts); put_slab_obj_exts(obj_exts); |
