* Re: [PATCH RFC 00/12] mm/slab, alloc_tag: reduce obj_ext memory waste
[not found] <20260715-b4-objext_split-v1-0-9a49c4ccf4c3@kernel.org>
@ 2026-07-15 15:32 ` Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-1-9a49c4ccf4c3@kernel.org>
` (9 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-15 15:32 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:10 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> The recent fixes for objext array handling inspired me to look into this
> finally. It's been bothering me that the memory usage of struct
> slabobj_ext depend only on config options and not whether the fields are
> actually used. So with both CONFIG_MEMCG=y and
> CONFIG_MEM_ALLOC_PROFILING=y there is always objcg field and codetag_ref
> field. And thus:
>
> 1) Having memory allocation profiling config-enabled but not
> boot-enabled means wasted memory on unused codetag_refs. This makes
> it less suitable for a general distro config and the page allocator
> side doesn't suffer from this, only slab and percpu.
>
> 2) Complementary, with memory allocation profiling enabled, there are
> caches/slabs that don't need the objcg field, so memory is wasted on
> those.
It's funny because yesterday I started working on a prototype for the
same optimization. But your patchset is much more mature, so I'll
focus instead on reviewing it.
>
> This series should solve the point 1) fully for slab, pcpuobj_ext
> handling can be perhaps improved similarly, haven't looked into that.
>
> For 2) it avoids allocating objcg fields for KMALLOC_NORMAL caches where
> we know they are not necessary because kmalloc() with __GFP_ACCOUNT will
> pick a KMALLOC_CGROUP type.
>
> The named kmem_caches are tricky. They can be created with SLAB_ACCOUNT
> and then we know objcg fields are always needed. But also they can be
> created without SLAB_ACCOUNT and then some allocations have
> __GFP_ACCOUNT and some not and we don't know that in advance.
Do you know how often this happens that a named cache with no
SLAB_ACCOUNT is used for __GFP_ACCOUNT allocation?
>
> A possible future solution is to introduce e.g. SLAB_MAYBE_ACCOUNT, add
> it to caches where we know __GFP_ACCOUNT is used, and only honour
> __GFP_ACCOUNT for those, while warning for an unexpected usage
> elsewhere.
I wonder if for such caches we could create two separate caches, one
serving __GFP_ACCOUNT and using extentions containing objcg and
another one for non-__GFP_ACCOUNT with optimized extentions?
>
> Only lightly tested, need to run at least some microbenchmarks to see if
> the now somewhat more complicated access to objcg is visible or not.
>
> Based on slab/for-next-fixes
>
> Git branch: https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/linux.git/log/?h=b4/objext_split
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> ---
> Vlastimil Babka (SUSE) (12):
> mm/slab: skip kfence objects in allocation profiling
> mm/slab: remove objs_per_slab()
> mm: move struct slabobj_ext to mm/slab.h
> mm/slab: make slab_obj_ext() determine object index
> mm/slab: abstract slabobj_ext.objcg access
> mm/slab: abstract slabobj_ext.ref access
> mm/slab: replace slab.stride with obj_exts_in_object
> mm/slab: change struct slabobj_ext to a union
> mm/slab: introduce slab_obj_ext_has_codetag()
> mm/slab: reduce slabobj_ext memory with allocation profiling disabled
> mm/slab: add slab_needs_objcg() helper
> mm/slab: stop allocating objcg pointers when unnecessary
>
> include/linux/memcontrol.h | 13 ----
> mm/kfence/core.c | 5 +-
> mm/kfence/kfence_test.c | 2 +-
> mm/memcontrol.c | 41 ++++++-----
> mm/slab.h | 169 ++++++++++++++++++++++++++++++++++++---------
> mm/slub.c | 162 +++++++++++++++++++++++++++----------------
> 6 files changed, 267 insertions(+), 125 deletions(-)
> ---
> base-commit: d9e6a7623938968e3752b67e37eaff097e559a54
> change-id: 20260714-b4-objext_split-da82426257d5
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 01/12] mm/slab: skip kfence objects in allocation profiling
[not found] ` <20260715-b4-objext_split-v1-1-9a49c4ccf4c3@kernel.org>
@ 2026-07-15 16:02 ` Suren Baghdasaryan
[not found] ` <ab9782bf-d3dd-4cb5-ae66-127b3a16330b@kernel.org>
0 siblings, 1 reply; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-15 16:02 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:10 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> struct kfence_metadata only has obj_exts with CONFIG_MEMCG.
I don't quite understand this statement. obj_exts are allocated when
either CONFIG_MEMCG or CONFIG_MEM_ALLOC_PROFILING is enabled.
> If it's
> enabled, it does also work for allocation profiling, but there's little
> value recording tags for KFENCE objects.
Unless we are leaking them, right?
> Furthermore it would complicate
> the upcoming changes, so just skip them in the slab hooks.
Ok, I can understand that. If we do this, we should document that
kfence objects are no longer tracked.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> ---
> mm/slub.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 0337e60db5ac..a4be70d080fb 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2352,6 +2352,9 @@ __alloc_tagging_slab_alloc_hook(struct kmem_cache *s, void *object, gfp_t flags,
> if (alloc_flags & SLAB_ALLOC_NO_RECURSE)
> return;
>
> + if (is_kfence_address(object))
> + return;
> +
> slab = virt_to_slab(object);
> obj_exts = prepare_slab_obj_exts_hook(s, slab, flags, alloc_flags, object);
> /*
> @@ -2399,6 +2402,9 @@ __alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p
> for (i = 0; i < objects; i++) {
> unsigned int off = obj_to_index(s, slab, p[i]);
>
> + if (is_kfence_address(p[i]))
> + continue;
> +
> alloc_tag_sub(&slab_obj_ext(slab, obj_exts, off)->ref, s->size);
> }
> put_slab_obj_exts(obj_exts);
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 02/12] mm/slab: remove objs_per_slab()
[not found] ` <20260715-b4-objext_split-v1-2-9a49c4ccf4c3@kernel.org>
@ 2026-07-15 16:13 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-15 16:13 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:10 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> The function has an unused kmem_cache argument and almost nothing uses
> it anyway; doing slab->objects is simpler. Remove it with the last two
> users. KUNIT_EXPECT_EQ() needs a cast to avoid "error: ‘typeof’ applied
> to a bit-field" but we don't need to keep a wrapper just for that.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Suren Baghdasayan <surenb@google.com>
> ---
> mm/kfence/kfence_test.c | 2 +-
> mm/slab.h | 6 ------
> mm/slub.c | 3 +--
> 3 files changed, 2 insertions(+), 9 deletions(-)
>
> diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c
> index de2d0f7d62b1..9867c03ef0ae 100644
> --- a/mm/kfence/kfence_test.c
> +++ b/mm/kfence/kfence_test.c
> @@ -295,7 +295,7 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
> * memcg accounting works correctly.
> */
> KUNIT_EXPECT_EQ(test, obj_to_index(s, slab, alloc), 0U);
> - KUNIT_EXPECT_EQ(test, objs_per_slab(s, slab), 1);
> + KUNIT_EXPECT_EQ(test, ((unsigned int)slab->objects), 1);
>
> if (policy == ALLOCATE_ANY)
> return alloc;
> diff --git a/mm/slab.h b/mm/slab.h
> index f5e336b6b6b0..01535e1e2d3c 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -330,12 +330,6 @@ static inline unsigned int obj_to_index(const struct kmem_cache *cache,
> return __obj_to_index(cache, slab_address(slab), obj);
> }
>
> -static inline int objs_per_slab(const struct kmem_cache *cache,
> - const struct slab *slab)
> -{
> - return slab->objects;
> -}
> -
> /*
> * State of the slab allocator.
> *
> diff --git a/mm/slub.c b/mm/slub.c
> index a4be70d080fb..9e25f2dce7a6 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2127,7 +2127,6 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> gfp_t gfp, unsigned int alloc_flags)
> {
> const bool allow_spin = alloc_flags_allow_spinning(alloc_flags);
> - unsigned int objects = objs_per_slab(s, slab);
> bool new_slab = alloc_flags & SLAB_ALLOC_NEW_SLAB;
> unsigned long new_exts;
> unsigned long old_exts;
> @@ -2183,7 +2182,7 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> #endif
> retry:
> old_exts = READ_ONCE(slab->obj_exts);
> - handle_failed_objexts_alloc(old_exts, vec, objects);
> + handle_failed_objexts_alloc(old_exts, vec, slab->objects);
>
> if (new_slab) {
> /*
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 03/12] mm: move struct slabobj_ext to mm/slab.h
[not found] ` <20260715-b4-objext_split-v1-3-9a49c4ccf4c3@kernel.org>
@ 2026-07-16 0:56 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 0:56 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:10 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> Users of include/linux/memcontrol.h don't need to see this internal
> structure. Further changes to the struct will reduce recompiling.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
> ---
> include/linux/memcontrol.h | 13 -------------
> mm/slab.h | 13 +++++++++++++
> 2 files changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index e1f46a0016fc..93869cc35c25 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -1440,19 +1440,6 @@ static inline void mem_cgroup_flush_workqueue(void) { }
> static inline int mem_cgroup_init(void) { return 0; }
> #endif /* CONFIG_MEMCG */
>
> -/*
> - * Extended information for slab objects stored as an array in page->memcg_data
> - * if MEMCG_DATA_OBJEXTS is set.
> - */
> -struct slabobj_ext {
> -#ifdef CONFIG_MEMCG
> - struct obj_cgroup *objcg;
> -#endif
> -#ifdef CONFIG_MEM_ALLOC_PROFILING
> - union codetag_ref ref;
> -#endif
> -} __aligned(8);
> -
> static inline struct lruvec *parent_lruvec(struct lruvec *lruvec)
> {
> struct mem_cgroup *memcg;
> diff --git a/mm/slab.h b/mm/slab.h
> index 01535e1e2d3c..7bd361447c54 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -549,6 +549,19 @@ static inline bool need_kmalloc_no_objext(void)
> return false;
> }
>
> +/*
> + * Extended information for slab objects stored as an array in page->memcg_data
> + * if MEMCG_DATA_OBJEXTS is set.
> + */
> +struct slabobj_ext {
> +#ifdef CONFIG_MEMCG
> + struct obj_cgroup *objcg;
> +#endif
> +#ifdef CONFIG_MEM_ALLOC_PROFILING
> + union codetag_ref ref;
> +#endif
> +} __aligned(8);
> +
> #ifdef CONFIG_SLAB_OBJ_EXT
>
> /*
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 04/12] mm/slab: make slab_obj_ext() determine object index
[not found] ` <20260715-b4-objext_split-v1-4-9a49c4ccf4c3@kernel.org>
@ 2026-07-16 1:02 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 1:02 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> All callers perform the same obj_to_index() calculation to pass the
> index. Simplify by passing object pointer instead and determining the
> index by slab_obj_ext().
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
> ---
> mm/memcontrol.c | 12 +++---------
> mm/slab.h | 14 ++++++++------
> mm/slub.c | 22 +++++++---------------
> 3 files changed, 18 insertions(+), 30 deletions(-)
>
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index 6dc4888a90f3..4e427286a88a 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -2865,15 +2865,13 @@ struct mem_cgroup *mem_cgroup_from_obj_slab(struct slab *slab, void *p)
> */
> unsigned long obj_exts;
> struct slabobj_ext *obj_ext;
> - unsigned int off;
>
> obj_exts = slab_obj_exts(slab);
> if (!obj_exts)
> return NULL;
>
> get_slab_obj_exts(obj_exts);
> - off = obj_to_index(slab->slab_cache, slab, p);
> - obj_ext = slab_obj_ext(slab, obj_exts, off);
> + obj_ext = slab_obj_ext(slab->slab_cache, slab, obj_exts, p);
> if (obj_ext->objcg) {
> struct obj_cgroup *objcg = obj_ext->objcg;
>
> @@ -3541,7 +3539,6 @@ bool __memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
> size_t obj_size = obj_full_size(s);
> struct obj_cgroup *objcg;
> struct slab *slab;
> - unsigned long off;
> size_t i;
>
> /*
> @@ -3616,8 +3613,7 @@ bool __memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
>
> obj_exts = slab_obj_exts(slab);
> get_slab_obj_exts(obj_exts);
> - off = obj_to_index(s, slab, p[i]);
> - obj_ext = slab_obj_ext(slab, obj_exts, off);
> + obj_ext = slab_obj_ext(s, slab, obj_exts, p[i]);
> obj_cgroup_get(objcg);
> obj_ext->objcg = objcg;
> put_slab_obj_exts(obj_exts);
> @@ -3635,10 +3631,8 @@ void __memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
> struct obj_cgroup *objcg;
> struct slabobj_ext *obj_ext;
> struct obj_stock_pcp *stock;
> - unsigned int off;
>
> - off = obj_to_index(s, slab, p[i]);
> - obj_ext = slab_obj_ext(slab, obj_exts, off);
> + obj_ext = slab_obj_ext(s, slab, obj_exts, p[i]);
> objcg = obj_ext->objcg;
> if (!objcg)
> continue;
> diff --git a/mm/slab.h b/mm/slab.h
> index 7bd361447c54..36d067d6e7c0 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -646,14 +646,16 @@ static inline unsigned int slab_get_stride(struct slab *slab)
> * Returns a pointer to the object extension associated with the object.
> * Must be called within a section covered by get/put_slab_obj_exts().
> */
> -static inline struct slabobj_ext *slab_obj_ext(struct slab *slab,
> - unsigned long obj_exts,
> - unsigned int index)
> +static inline struct slabobj_ext *
> +slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> + const void *obj)
> {
> struct slabobj_ext *obj_ext;
> + unsigned int index;
>
> VM_WARN_ON_ONCE(obj_exts != slab_obj_exts(slab));
>
> + index = obj_to_index(s, slab, obj);
> obj_ext = (struct slabobj_ext *)(obj_exts +
> slab_get_stride(slab) * index);
> return kasan_reset_tag(obj_ext);
> @@ -669,9 +671,9 @@ static inline unsigned long slab_obj_exts(struct slab *slab)
> return 0;
> }
>
> -static inline struct slabobj_ext *slab_obj_ext(struct slab *slab,
> - unsigned long obj_exts,
> - unsigned int index)
> +static inline struct slabobj_ext *
> +slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> + const void *obj)
> {
> return NULL;
> }
> diff --git a/mm/slub.c b/mm/slub.c
> index 9e25f2dce7a6..5e3f53bcd0d3 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2070,11 +2070,10 @@ static inline void mark_obj_codetag_empty(const void *obj)
> obj_slab = virt_to_slab(obj);
> slab_exts = slab_obj_exts(obj_slab);
> if (slab_exts) {
> + struct slabobj_ext *ext;
> +
> get_slab_obj_exts(slab_exts);
> - unsigned int offs = obj_to_index(obj_slab->slab_cache,
> - obj_slab, obj);
> - struct slabobj_ext *ext = slab_obj_ext(obj_slab,
> - slab_exts, offs);
> + ext = slab_obj_ext(obj_slab->slab_cache, obj_slab, slab_exts, obj);
>
> if (unlikely(is_codetag_empty(&ext->ref))) {
> put_slab_obj_exts(slab_exts);
> @@ -2362,10 +2361,8 @@ __alloc_tagging_slab_alloc_hook(struct kmem_cache *s, void *object, gfp_t flags,
> * check should be added before alloc_tag_add().
> */
> if (obj_exts) {
> - unsigned int obj_idx = obj_to_index(s, slab, object);
> -
> get_slab_obj_exts(obj_exts);
> - obj_ext = slab_obj_ext(slab, obj_exts, obj_idx);
> + obj_ext = slab_obj_ext(s, slab, obj_exts, object);
> alloc_tag_add(&obj_ext->ref, current->alloc_tag, s->size);
> put_slab_obj_exts(obj_exts);
> } else {
> @@ -2386,7 +2383,6 @@ static noinline void
> __alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
> int objects)
> {
> - int i;
> unsigned long obj_exts;
>
> /* slab->obj_exts might not be NULL if it was created for MEMCG accounting. */
> @@ -2398,13 +2394,11 @@ __alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p
> return;
>
> get_slab_obj_exts(obj_exts);
> - for (i = 0; i < objects; i++) {
> - unsigned int off = obj_to_index(s, slab, p[i]);
> -
> + for (int i = 0; i < objects; i++) {
> if (is_kfence_address(p[i]))
> continue;
>
> - alloc_tag_sub(&slab_obj_ext(slab, obj_exts, off)->ref, s->size);
> + alloc_tag_sub(&slab_obj_ext(s, slab, obj_exts, p[i])->ref, s->size);
> }
> put_slab_obj_exts(obj_exts);
> }
> @@ -2489,7 +2483,6 @@ bool memcg_slab_post_charge(void *p, gfp_t flags)
> struct kmem_cache *s;
> struct page *page;
> struct slab *slab;
> - unsigned long off;
>
> page = virt_to_page(p);
> if (PageLargeKmalloc(page)) {
> @@ -2529,8 +2522,7 @@ bool memcg_slab_post_charge(void *p, gfp_t flags)
> obj_exts = slab_obj_exts(slab);
> if (obj_exts) {
> get_slab_obj_exts(obj_exts);
> - off = obj_to_index(s, slab, p);
> - obj_ext = slab_obj_ext(slab, obj_exts, off);
> + obj_ext = slab_obj_ext(s, slab, obj_exts, p);
> if (unlikely(obj_ext->objcg)) {
> put_slab_obj_exts(obj_exts);
> return true;
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 05/12] mm/slab: abstract slabobj_ext.objcg access
[not found] ` <20260715-b4-objext_split-v1-5-9a49c4ccf4c3@kernel.org>
@ 2026-07-16 1:27 ` Suren Baghdasaryan
2026-07-16 13:58 ` Vlastimil Babka (SUSE)
0 siblings, 1 reply; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 1:27 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> In preparation for changes to the structure, abstract access to the
> objcg field with a slab_obj_ext_objcgp() function.
> Rename the field to _objcg to make an unexpected direct access a compile
> error.
>
> No functional change intended.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> ---
> mm/kfence/core.c | 2 +-
> mm/memcontrol.c | 23 +++++++++++++++--------
> mm/slab.h | 9 ++++++++-
> mm/slub.c | 2 +-
> 4 files changed, 25 insertions(+), 11 deletions(-)
>
> diff --git a/mm/kfence/core.c b/mm/kfence/core.c
> index 6577bd76954e..717e8baf7e5d 100644
> --- a/mm/kfence/core.c
> +++ b/mm/kfence/core.c
> @@ -1249,7 +1249,7 @@ void __kfence_free(void *addr)
> struct kfence_metadata *meta = addr_to_metadata((unsigned long)addr);
>
> #ifdef CONFIG_MEMCG
> - KFENCE_WARN_ON(meta->obj_exts.objcg);
> + KFENCE_WARN_ON(*slab_obj_ext_objcgp(&meta->obj_exts));
> #endif
> /*
> * If the objects of the cache are SLAB_TYPESAFE_BY_RCU, defer freeing
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index 4e427286a88a..6303a2b1a9d0 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -2865,6 +2865,7 @@ struct mem_cgroup *mem_cgroup_from_obj_slab(struct slab *slab, void *p)
> */
> unsigned long obj_exts;
> struct slabobj_ext *obj_ext;
> + struct obj_cgroup *objcg;
>
> obj_exts = slab_obj_exts(slab);
> if (!obj_exts)
> @@ -2872,9 +2873,8 @@ struct mem_cgroup *mem_cgroup_from_obj_slab(struct slab *slab, void *p)
>
> get_slab_obj_exts(obj_exts);
> obj_ext = slab_obj_ext(slab->slab_cache, slab, obj_exts, p);
> - if (obj_ext->objcg) {
> - struct obj_cgroup *objcg = obj_ext->objcg;
> -
> + objcg = *slab_obj_ext_objcgp(obj_ext);
> + if (objcg) {
> put_slab_obj_exts(obj_exts);
> return obj_cgroup_memcg(objcg);
> }
> @@ -3577,6 +3577,7 @@ bool __memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
> unsigned long obj_exts;
> struct slabobj_ext *obj_ext;
> struct obj_stock_pcp *stock;
> + struct obj_cgroup **objcgp;
>
> slab = virt_to_slab(p[i]);
>
> @@ -3612,10 +3613,15 @@ bool __memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
> unlock_stock(stock);
>
> obj_exts = slab_obj_exts(slab);
> +
> get_slab_obj_exts(obj_exts);
> +
> obj_ext = slab_obj_ext(s, slab, obj_exts, p[i]);
> + objcgp = slab_obj_ext_objcgp(obj_ext);
> +
> obj_cgroup_get(objcg);
> - obj_ext->objcg = objcg;
> + *objcgp = objcg;
> +
> put_slab_obj_exts(obj_exts);
> }
>
> @@ -3628,16 +3634,17 @@ void __memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
> size_t obj_size = obj_full_size(s);
>
> for (int i = 0; i < objects; i++) {
> - struct obj_cgroup *objcg;
> + struct obj_cgroup **objcgp, *objcg;
> struct slabobj_ext *obj_ext;
> struct obj_stock_pcp *stock;
>
> obj_ext = slab_obj_ext(s, slab, obj_exts, p[i]);
> - objcg = obj_ext->objcg;
> - if (!objcg)
> + objcgp = slab_obj_ext_objcgp(obj_ext);
> + if (!*objcgp)
> continue;
>
> - obj_ext->objcg = NULL;
> + objcg = *objcgp;
> + *objcgp = NULL;
>
> stock = trylock_stock();
> __refill_obj_stock(objcg, stock, obj_size, true);
> diff --git a/mm/slab.h b/mm/slab.h
> index 36d067d6e7c0..789bd292075f 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -555,7 +555,7 @@ static inline bool need_kmalloc_no_objext(void)
> */
> struct slabobj_ext {
> #ifdef CONFIG_MEMCG
> - struct obj_cgroup *objcg;
> + struct obj_cgroup *_objcg;
> #endif
> #ifdef CONFIG_MEM_ALLOC_PROFILING
> union codetag_ref ref;
> @@ -661,6 +661,13 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> return kasan_reset_tag(obj_ext);
> }
>
> +#ifdef CONFIG_MEMCG
> +static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ext)
I understand why you need to return obj_cgroup** but maybe instead we
can have a separate setter function and just return a pointer here?
That would also help catch cases when someone wants to set
obj_ext._objcg that was optimized away (for that the setter would need
an additional parameter to identify whether we allocated optimized
objext vector).
> +{
> + return &obj_ext->_objcg;
> +}
> +#endif
> +
> int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> gfp_t gfp, unsigned int alloc_flags);
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 5e3f53bcd0d3..48e10198a3ce 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2523,7 +2523,7 @@ bool memcg_slab_post_charge(void *p, gfp_t flags)
> if (obj_exts) {
> get_slab_obj_exts(obj_exts);
> obj_ext = slab_obj_ext(s, slab, obj_exts, p);
> - if (unlikely(obj_ext->objcg)) {
> + if (unlikely(*slab_obj_ext_objcgp(obj_ext))) {
> put_slab_obj_exts(obj_exts);
> return true;
> }
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 06/12] mm/slab: abstract slabobj_ext.ref access
[not found] ` <20260715-b4-objext_split-v1-6-9a49c4ccf4c3@kernel.org>
@ 2026-07-16 1:28 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 1:28 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> In preparation for changes to the structure, abstract access to the ref
> field with a slab_obj_ext_codetag_ref() function. Rename the field to
> _ctref to make an unexpected direct access a compile error.
>
> No functional change intended.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
> ---
> mm/slab.h | 10 +++++++++-
> mm/slub.c | 42 ++++++++++++++++++++++++++++--------------
> 2 files changed, 37 insertions(+), 15 deletions(-)
>
> diff --git a/mm/slab.h b/mm/slab.h
> index 789bd292075f..e3f8e42070f1 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -558,7 +558,7 @@ struct slabobj_ext {
> struct obj_cgroup *_objcg;
> #endif
> #ifdef CONFIG_MEM_ALLOC_PROFILING
> - union codetag_ref ref;
> + union codetag_ref _ctref;
> #endif
> } __aligned(8);
>
> @@ -668,6 +668,14 @@ static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ex
> }
> #endif
>
> +#ifdef CONFIG_MEM_ALLOC_PROFILING
> +static inline union codetag_ref *
> +slab_obj_ext_codetag_ref(struct slab *slab, struct slabobj_ext *obj_ext)
> +{
> + return &obj_ext->_ctref;
> +}
> +#endif
> +
> int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> gfp_t gfp, unsigned int alloc_flags);
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 48e10198a3ce..2bfcabc4c51a 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2071,18 +2071,20 @@ static inline void mark_obj_codetag_empty(const void *obj)
> slab_exts = slab_obj_exts(obj_slab);
> if (slab_exts) {
> struct slabobj_ext *ext;
> + union codetag_ref *ref;
>
> get_slab_obj_exts(slab_exts);
> ext = slab_obj_ext(obj_slab->slab_cache, obj_slab, slab_exts, obj);
> + ref = slab_obj_ext_codetag_ref(obj_slab, ext);
>
> - if (unlikely(is_codetag_empty(&ext->ref))) {
> + if (unlikely(is_codetag_empty(ref))) {
> put_slab_obj_exts(slab_exts);
> return;
> }
>
> /* codetag should be NULL here */
> - WARN_ON(ext->ref.ct);
> - set_codetag_empty(&ext->ref);
> + WARN_ON(ref->ct);
> + set_codetag_empty(ref);
> put_slab_obj_exts(slab_exts);
> }
> }
> @@ -2092,19 +2094,22 @@ static inline bool mark_failed_objexts_alloc(struct slab *slab)
> return cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL) == 0;
> }
>
> -static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
> - struct slabobj_ext *vec, unsigned int objects)
> +static inline void handle_failed_objexts_alloc(struct slab *slab,
> + unsigned long obj_exts, struct slabobj_ext *vec)
> {
> /*
> * If vector previously failed to allocate then we have live
> * objects with no tag reference. Mark all references in this
> * vector as empty to avoid warnings later on.
> */
> - if (obj_exts == OBJEXTS_ALLOC_FAIL) {
> - unsigned int i;
> + if (obj_exts != OBJEXTS_ALLOC_FAIL)
> + return;
> +
> + for (unsigned int i = 0; i < slab->objects; i++) {
> + union codetag_ref *ref = slab_obj_ext_codetag_ref(slab, vec);
>
> - for (i = 0; i < objects; i++)
> - set_codetag_empty(&vec[i].ref);
> + set_codetag_empty(ref);
> + vec++;
> }
> }
>
> @@ -2112,8 +2117,8 @@ static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
>
> static inline void mark_obj_codetag_empty(const void *obj) {}
> static inline bool mark_failed_objexts_alloc(struct slab *slab) { return false; }
> -static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
> - struct slabobj_ext *vec, unsigned int objects) {}
> +static inline void handle_failed_objexts_alloc(struct slab *slab,
> + unsigned long obj_exts, struct slabobj_ext *vec) {}
>
> #endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
>
> @@ -2181,7 +2186,7 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> #endif
> retry:
> old_exts = READ_ONCE(slab->obj_exts);
> - handle_failed_objexts_alloc(old_exts, vec, slab->objects);
> + handle_failed_objexts_alloc(slab, old_exts, vec);
>
> if (new_slab) {
> /*
> @@ -2361,9 +2366,15 @@ __alloc_tagging_slab_alloc_hook(struct kmem_cache *s, void *object, gfp_t flags,
> * check should be added before alloc_tag_add().
> */
> if (obj_exts) {
> + union codetag_ref *ref;
> +
> get_slab_obj_exts(obj_exts);
> +
> obj_ext = slab_obj_ext(s, slab, obj_exts, object);
> - alloc_tag_add(&obj_ext->ref, current->alloc_tag, s->size);
> + ref = slab_obj_ext_codetag_ref(slab, obj_ext);
> +
> + alloc_tag_add(ref, current->alloc_tag, s->size);
> +
> put_slab_obj_exts(obj_exts);
> } else {
> alloc_tag_set_inaccurate(current->alloc_tag);
> @@ -2395,10 +2406,13 @@ __alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p
>
> get_slab_obj_exts(obj_exts);
> for (int i = 0; i < objects; i++) {
> + struct slabobj_ext *ext;
> +
> if (is_kfence_address(p[i]))
> continue;
>
> - alloc_tag_sub(&slab_obj_ext(s, slab, obj_exts, p[i])->ref, s->size);
> + ext = slab_obj_ext(s, slab, obj_exts, p[i]);
> + alloc_tag_sub(slab_obj_ext_codetag_ref(slab, ext), s->size);
> }
> put_slab_obj_exts(obj_exts);
> }
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 07/12] mm/slab: replace slab.stride with obj_exts_in_object
[not found] ` <20260715-b4-objext_split-v1-7-9a49c4ccf4c3@kernel.org>
@ 2026-07-16 1:44 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 1:44 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> The stride field is used to convert object index to an slabobj_ext so
> both compact arrays (kmalloc() or in-slab-leftover) and spread
> in-object-padding obj_ext layouts are supported.
>
> In practice thus the stride is always sizeof(slabobj_ext) or s->size.
>
> This simplifies the calculations, but with the upcoming slabobj_ext
> handling changes, it will be easier to stop storing the stride and
> instead just have a flag whether obj_ext is in the object padding.
> obj_exts_in_object() can then rely on this flag and slab_obj_ext()
> can use that to determine the stride.
>
> No functional change intended. Performance impact TBD, hopefully
> in the noise.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
> ---
> mm/slab.h | 43 ++++++++++++++++++++++++-------------------
> mm/slub.c | 42 ++++++++++++++++--------------------------
> 2 files changed, 40 insertions(+), 45 deletions(-)
>
> diff --git a/mm/slab.h b/mm/slab.h
> index e3f8e42070f1..3ad9777ad600 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -81,10 +81,10 @@ struct freelist_counters {
> #ifdef CONFIG_64BIT
> /*
> * Some optimizations use free bits in 'counters' field
> - * to save memory. In case ->stride field is not available,
> + * to save memory. If these free bits are not available,
> * such optimizations are disabled.
> */
> - unsigned int stride;
> + unsigned obj_exts_in_object:1;
> #endif
> };
> };
> @@ -617,22 +617,20 @@ static inline void put_slab_obj_exts(unsigned long obj_exts)
> }
>
> #ifdef CONFIG_64BIT
> -static inline void slab_set_stride(struct slab *slab, unsigned int stride)
> +static inline bool obj_exts_in_object(struct slab *slab)
> {
> - slab->stride = stride;
> -}
> -static inline unsigned int slab_get_stride(struct slab *slab)
> -{
> - return slab->stride;
> + /*
> + * Note we cannot rely on the SLAB_OBJ_EXT_IN_OBJ flag here and need to
> + * check the per-slab bit. A cache can have SLAB_OBJ_EXT_IN_OBJ set, but
> + * allocations within_slab_leftover are preferred. And those may be
> + * possible or not depending on the particular slab's size.
> + */
> + return slab->obj_exts_in_object;
> }
> #else
> -static inline void slab_set_stride(struct slab *slab, unsigned int stride)
> +static inline bool obj_exts_in_object(struct slab *slab)
> {
> - VM_WARN_ON_ONCE(stride != sizeof(struct slabobj_ext));
> -}
> -static inline unsigned int slab_get_stride(struct slab *slab)
> -{
> - return sizeof(struct slabobj_ext);
> + return false;
> }
> #endif
>
> @@ -656,8 +654,14 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> VM_WARN_ON_ONCE(obj_exts != slab_obj_exts(slab));
>
> index = obj_to_index(s, slab, obj);
> - obj_ext = (struct slabobj_ext *)(obj_exts +
> - slab_get_stride(slab) * index);
> +
> + if (!obj_exts_in_object(slab)) {
> + obj_ext = ((struct slabobj_ext *)obj_exts) + index;
> + } else {
> + unsigned int stride = s->size;
> + obj_ext = (struct slabobj_ext *)(obj_exts + index * stride);
> + }
> +
> return kasan_reset_tag(obj_ext);
> }
>
> @@ -693,9 +697,10 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> return NULL;
> }
>
> -static inline void slab_set_stride(struct slab *slab, unsigned int stride) { }
> -static inline unsigned int slab_get_stride(struct slab *slab) { return 0; }
> -
> +static inline bool obj_exts_in_object(struct slab *slab)
> +{
> + return false;
> +}
>
> #endif /* CONFIG_SLAB_OBJ_EXT */
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 2bfcabc4c51a..98a14e5842a2 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -870,18 +870,6 @@ static inline bool obj_exts_in_slab(struct kmem_cache *s, struct slab *slab)
> #endif
>
> #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> -static bool obj_exts_in_object(struct kmem_cache *s, struct slab *slab)
> -{
> - /*
> - * Note we cannot rely on the SLAB_OBJ_EXT_IN_OBJ flag here and need to
> - * check the stride. A cache can have SLAB_OBJ_EXT_IN_OBJ set, but
> - * allocations within_slab_leftover are preferred. And those may be
> - * possible or not depending on the particular slab's size.
> - */
> - return obj_exts_in_slab(s, slab) &&
> - (slab_get_stride(slab) == s->size);
> -}
> -
> static unsigned int obj_exts_offset_in_object(struct kmem_cache *s)
> {
> unsigned int offset = get_info_end(s);
> @@ -896,16 +884,20 @@ static unsigned int obj_exts_offset_in_object(struct kmem_cache *s)
>
> return offset;
> }
> -#else
> -static inline bool obj_exts_in_object(struct kmem_cache *s, struct slab *slab)
> +
> +static inline void slab_set_obj_exts_in_object(struct slab *slab)
> {
> - return false;
> + slab->obj_exts_in_object = 1;
> }
> -
> +#else
> static inline unsigned int obj_exts_offset_in_object(struct kmem_cache *s)
> {
> return 0;
> }
> +
> +static inline void slab_set_obj_exts_in_object(struct slab *slab)
> +{
> +}
> #endif
>
> #ifdef CONFIG_SLUB_DEBUG
> @@ -1206,7 +1198,7 @@ static void print_trailer(struct kmem_cache *s, struct slab *slab, u8 *p)
>
> off += kasan_metadata_size(s, false);
>
> - if (obj_exts_in_object(s, slab))
> + if (obj_exts_in_object(slab))
> off += sizeof(struct slabobj_ext);
>
> if (off != size_from_object(s))
> @@ -1411,7 +1403,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct slab *slab, u8 *p)
>
> off += kasan_metadata_size(s, false);
>
> - if (obj_exts_in_object(s, slab))
> + if (obj_exts_in_object(slab))
> off += sizeof(struct slabobj_ext);
>
> if (size_from_object(s) == off)
> @@ -1439,7 +1431,7 @@ slab_pad_check(struct kmem_cache *s, struct slab *slab)
> length = slab_size(slab);
> end = start + length;
>
> - if (obj_exts_in_slab(s, slab) && !obj_exts_in_object(s, slab)) {
> + if (obj_exts_in_slab(s, slab) && !obj_exts_in_object(slab)) {
> remainder = length;
> remainder -= obj_exts_offset_in_slab(s, slab);
> remainder -= obj_exts_size_in_slab(slab);
> @@ -2253,9 +2245,6 @@ static void alloc_slab_obj_exts_early(struct kmem_cache *s, struct slab *slab)
> void *addr;
> unsigned long obj_exts;
>
> - /* Initialize stride early to avoid memory ordering issues */
> - slab_set_stride(slab, sizeof(struct slabobj_ext));
> -
> if (!need_slab_obj_exts(s))
> return;
>
> @@ -2289,7 +2278,7 @@ static void alloc_slab_obj_exts_early(struct kmem_cache *s, struct slab *slab)
> obj_exts |= MEMCG_DATA_OBJEXTS;
> #endif
> slab->obj_exts = obj_exts;
> - slab_set_stride(slab, s->size);
> + slab_set_obj_exts_in_object(slab);
> }
> }
>
> @@ -3402,9 +3391,10 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags,
> stat(s, ORDER_FALLBACK);
> }
>
> + /* Initializes frozen, inuse, and any extra 64bit-only flags */
> + slab->counters = 0;
> +
> slab->objects = oo_objects(oo);
> - slab->inuse = 0;
> - slab->frozen = 0;
>
> slab->slab_cache = s;
>
> @@ -6537,7 +6527,7 @@ static inline size_t slab_ksize(struct slab *slab)
> */
> if (s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER))
> return s->inuse;
> - else if (obj_exts_in_object(s, slab))
> + else if (obj_exts_in_object(slab))
> return s->inuse;
> /*
> * Else we can use all the padding etc for the allocation
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 05/12] mm/slab: abstract slabobj_ext.objcg access
2026-07-16 1:27 ` [PATCH RFC 05/12] mm/slab: abstract slabobj_ext.objcg access Suren Baghdasaryan
@ 2026-07-16 13:58 ` Vlastimil Babka (SUSE)
2026-07-16 15:27 ` Suren Baghdasaryan
0 siblings, 1 reply; 16+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-07-16 13:58 UTC (permalink / raw)
To: Suren Baghdasaryan
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On 7/16/26 03:27, Suren Baghdasaryan wrote:
> On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
> <vbabka@kernel.org> wrote:
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -555,7 +555,7 @@ static inline bool need_kmalloc_no_objext(void)
>> */
>> struct slabobj_ext {
>> #ifdef CONFIG_MEMCG
>> - struct obj_cgroup *objcg;
>> + struct obj_cgroup *_objcg;
>> #endif
>> #ifdef CONFIG_MEM_ALLOC_PROFILING
>> union codetag_ref ref;
>> @@ -661,6 +661,13 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
>> return kasan_reset_tag(obj_ext);
>> }
>>
>> +#ifdef CONFIG_MEMCG
>> +static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ext)
>
> I understand why you need to return obj_cgroup** but maybe instead we
> can have a separate setter function and just return a pointer here?
Yeah I rewrote it now and it looks better. Thanks! It ended up like this due
to some previous attempt I made.
> That would also help catch cases when someone wants to set
> obj_ext._objcg that was optimized away (for that the setter would need
> an additional parameter to identify whether we allocated optimized
> objext vector).
It would need passing the slab parameter to assert
slab_obj_ext_has_codetag() in debug mode. I don't think it's worth it given
the get/set is only called from few specialized places.
>
>> +{
>> + return &obj_ext->_objcg;
>> +}
>> +#endif
>> +
>> int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
>> gfp_t gfp, unsigned int alloc_flags);
>>
>> diff --git a/mm/slub.c b/mm/slub.c
>> index 5e3f53bcd0d3..48e10198a3ce 100644
>> --- a/mm/slub.c
>> +++ b/mm/slub.c
>> @@ -2523,7 +2523,7 @@ bool memcg_slab_post_charge(void *p, gfp_t flags)
>> if (obj_exts) {
>> get_slab_obj_exts(obj_exts);
>> obj_ext = slab_obj_ext(s, slab, obj_exts, p);
>> - if (unlikely(obj_ext->objcg)) {
>> + if (unlikely(*slab_obj_ext_objcgp(obj_ext))) {
>> put_slab_obj_exts(obj_exts);
>> return true;
>> }
>>
>> --
>> 2.55.0
>>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 08/12] mm/slab: change struct slabobj_ext to a union
[not found] ` <CAJuCfpGq3Yv8Dq=2mPgR5LGC=40VSNTA6mg4BjTRE0ADXMZkbg@mail.gmail.com>
@ 2026-07-16 14:43 ` Vlastimil Babka (SUSE)
2026-07-16 15:28 ` Suren Baghdasaryan
0 siblings, 1 reply; 16+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-07-16 14:43 UTC (permalink / raw)
To: Suren Baghdasaryan
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On 7/16/26 06:11, Suren Baghdasaryan wrote:
> On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
> <vbabka@kernel.org> wrote:
>> No functional change intended, the layout is still effectively static.
>>
>> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
>
> This is much cleaner than what I was preparing. Nicely done!
>
> Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Thanks!
>> ---
>> mm/slab.h | 41 +++++++++++++++++++++++++++++++++--------
>> mm/slub.c | 17 +++++++++--------
>> 2 files changed, 42 insertions(+), 16 deletions(-)
>>
>> diff --git a/mm/slab.h b/mm/slab.h
>> index 3ad9777ad600..359ab8caf61e 100644
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -554,14 +554,34 @@ static inline bool need_kmalloc_no_objext(void)
>> * if MEMCG_DATA_OBJEXTS is set.
>> */
>> struct slabobj_ext {
>
> Perhaps we should add a comment here stating that every element of
> this union should be pointer-sized?
>
OK, how about this?
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -550,10 +550,14 @@ static inline bool need_kmalloc_no_objext(void)
}
/*
- * Extended information for slab objects stored as an array in page->memcg_data
- * if MEMCG_DATA_OBJEXTS is set.
+ * Extended information for slab objects stored as a pointer to an array in
+ * slab->obj_exts (aliasing page->memcg_data) if MEMCG_DATA_OBJEXTS is set.
*/
struct slabobj_ext {
+ /*
+ * All elements of the union should be pointer-sized to avoid memory
+ * waste
+ */
union {
#ifdef CONFIG_MEMCG
struct obj_cgroup *_objcg;
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 09/12] mm/slab: introduce slab_obj_ext_has_codetag()
[not found] ` <CAJuCfpGkpe=5O_vW9VKqKFxrBO+QquCD+mXth_qeUSqcWcW6hA@mail.gmail.com>
@ 2026-07-16 14:47 ` Vlastimil Babka (SUSE)
0 siblings, 0 replies; 16+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-07-16 14:47 UTC (permalink / raw)
To: Suren Baghdasaryan
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On 7/16/26 06:25, Suren Baghdasaryan wrote:
> On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
> <vbabka@kernel.org> wrote:
>>
>> mem_alloc_profiling_enabled() allows evaluating (with a static key) if
>> memory profiling is currently enabled. mem_profiling_support is a
>> variable where false means it's not possible to enable it anymore,
>> because the system was booted with "never" or it was later shut down.
>> This is possible to query by mem_alloc_profiling_permanently_disabled().
>>
>> To make slabobj_ext array size handling dynamic, we need a snapshot of
>> mem_alloc_profiling_permanently_disabled() early in boot, so that's not
>> affected by a later shutdown. We also need it to be static key based for
>> performance. Neither mem_alloc_profiling_enabled() nor
>> mem_alloc_profiling_permanently_disabled() satisfy this.
>>
>> Therefore introduce slab_obj_ext_has_codetag() with an underlying static
>> key for that use case. Its state is made to reflect the result of
>> mem_alloc_profiling_permanently_disabled() during kmem_cache_init(),
>> which does happen after setup_early_mem_profiling().
>>
>> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
>
> Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Thanks!
>> +/*
>> + * Make sure the static key used by slab_obj_ext_has_codetag() reflects the
>> + * value of !mem_alloc_profiling_permanently_disabled()
>> + *
>> + * Any later mem alloc profiling shutdown won't be reflected in the static key
>> + * because obj_exts with codetags might already exist.
>> + */
>> +static void __init slab_obj_ext_has_codetag_init(void)
>> +{
>> + bool key_enabled = IS_ENABLED(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT);
>
> nit: This seems a bit indirect. Reader needs to remember that
> slab_obj_ext_has_codetag_key is initialized based on
> CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT. Wouldn't below code be
> simpler?:
>
> bool need_codetag = !mem_alloc_profiling_permanently_disabled();
> if (need_codetag != static_key_enabled(&slab_obj_ext_has_codetag_key)) {
> if (need_codetag)
> static_branch_enable(&slab_obj_ext_has_codetag_key);
> else
> static_branch_disable(&slab_obj_ext_has_codetag_key);
> }
>
> It might be less performant but who cares, it's __init function used
> only one time.
Good idea, will do!
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 12/12] mm/slab: stop allocating objcg pointers when unnecessary
[not found] ` <CAJuCfpHuXu3BDf93zeBQWSW_k5wApegp44rHoZwk5Ym6xxbqEA@mail.gmail.com>
@ 2026-07-16 15:08 ` Vlastimil Babka (SUSE)
2026-07-16 15:32 ` Suren Baghdasaryan
0 siblings, 1 reply; 16+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-07-16 15:08 UTC (permalink / raw)
To: Suren Baghdasaryan
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On 7/16/26 06:46, Suren Baghdasaryan wrote:
> Maybe now we should rename static_obj_ext_size() to
> static_obj_ext_max_size() as it reflects the max possible size of
> slabobj_ext?
Hm with _max_size() it doesn't have to be called static_ anymore?
But maybe we can get rid of it completely.
The only caller is calculate_sizes():
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
if (slab_args_unmergeable(args, s->flags) &&
(aligned_size - size >= static_obj_ext_size()))
s->flags |= SLAB_OBJ_EXT_IN_OBJ;
#endif
We don't have slab pointer to pass to static_obj_ext_max_size().
But we should be able to figure it out from the cache via
cache_needs_objcg().
So we'd need cache_obj_ext_size()?
The static max size here works, but may prevent SLAB_OBJ_EXT_IN_OBJ
needlessly if padding can only fit codetag_ref and not objcg, but
we don't need objcg.
Which is probably only theoretical at this point as kmalloc_normal
caches (that have no objcg) have no padding, at least without
slab_debug. But still.
>> + 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
>> @@ -741,7 +749,7 @@ static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ex
>> static inline union codetag_ref *
>> slab_obj_ext_codetag_ref(struct slab *slab, struct slabobj_ext *obj_ext)
>> {
>> - 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 771d73abacb6..09c4931e5435 100644
>> --- a/mm/slub.c
>> +++ b/mm/slub.c
>> @@ -2503,6 +2503,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);
>>
>> --
>> 2.55.0
>>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 01/12] mm/slab: skip kfence objects in allocation profiling
[not found] ` <ab9782bf-d3dd-4cb5-ae66-127b3a16330b@kernel.org>
@ 2026-07-16 15:24 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 15:24 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Thu, Jul 16, 2026 at 2:11 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> On 7/15/26 18:02, Suren Baghdasaryan wrote:
> > On Wed, Jul 15, 2026 at 3:10 AM Vlastimil Babka (SUSE)
> > <vbabka@kernel.org> wrote:
> >>
> >> struct kfence_metadata only has obj_exts with CONFIG_MEMCG.
> >
> > I don't quite understand this statement. obj_exts are allocated when
> > either CONFIG_MEMCG or CONFIG_MEM_ALLOC_PROFILING is enabled.
>
> See in mm/kfence/kfence.h
>
> struct kfence_metadata {
> ...
> #ifdef CONFIG_MEMCG
> struct slabobj_ext obj_exts;
> #endif
> ...
>
> then in mm/kfence/core.c kfence_init_pool()
>
> #ifdef CONFIG_MEMCG
> struct slab *slab = page_slab(page);
> slab->obj_exts = (unsigned long)&kfence_metadata_init[i / 2 - 1].obj_exts |
> MEMCG_DATA_OBJEXTS;
> #endif
>
> So the slab kfence fakes only has this pre-inited obj_exts
> with CONFIG_MEMCG.
>
> What happens if we run memalloc profiling without MEMCG and this
> fake slab doesn't have a pre-assigned obj_exts? I guess
> __alloc_tagging_slab_alloc_hook() will allocate it via
> prepare_slab_obj_exts_hook().
>
> But it's something that was done consciously and probably
> just accidentally works.
Ok, I see. Maybe you can expand this description to explain the
details more thoroughly? This whole kfence.obj_exts deal is not very
intuitive.
>
> >> If it's
> >> enabled, it does also work for allocation profiling, but there's little
> >> value recording tags for KFENCE objects.
> >
> > Unless we are leaking them, right?
>
> Well if there are leaks in a particular callsite, we should see that from all
> the allocations that don't end up in kfence (as kfence allocations are rare).
> So we are very unlikely to miss a leak due to this.
Ok, makes sense. Thanks for the explanation!
>
> >> Furthermore it would complicate
> >> the upcoming changes, so just skip them in the slab hooks.
> >
> > Ok, I can understand that. If we do this, we should document that
> > kfence objects are no longer tracked.
> >
> >>
> >> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> >> ---
> >> mm/slub.c | 6 ++++++
> >> 1 file changed, 6 insertions(+)
> >>
> >> diff --git a/mm/slub.c b/mm/slub.c
> >> index 0337e60db5ac..a4be70d080fb 100644
> >> --- a/mm/slub.c
> >> +++ b/mm/slub.c
> >> @@ -2352,6 +2352,9 @@ __alloc_tagging_slab_alloc_hook(struct kmem_cache *s, void *object, gfp_t flags,
> >> if (alloc_flags & SLAB_ALLOC_NO_RECURSE)
> >> return;
> >>
> >> + if (is_kfence_address(object))
> >> + return;
> >> +
> >> slab = virt_to_slab(object);
> >> obj_exts = prepare_slab_obj_exts_hook(s, slab, flags, alloc_flags, object);
> >> /*
> >> @@ -2399,6 +2402,9 @@ __alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p
> >> for (i = 0; i < objects; i++) {
> >> unsigned int off = obj_to_index(s, slab, p[i]);
> >>
> >> + if (is_kfence_address(p[i]))
> >> + continue;
> >> +
> >> alloc_tag_sub(&slab_obj_ext(slab, obj_exts, off)->ref, s->size);
> >> }
> >> put_slab_obj_exts(obj_exts);
> >>
> >> --
> >> 2.55.0
> >>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 05/12] mm/slab: abstract slabobj_ext.objcg access
2026-07-16 13:58 ` Vlastimil Babka (SUSE)
@ 2026-07-16 15:27 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 15:27 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Thu, Jul 16, 2026 at 6:58 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> On 7/16/26 03:27, Suren Baghdasaryan wrote:
> > On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
> > <vbabka@kernel.org> wrote:
> >> --- a/mm/slab.h
> >> +++ b/mm/slab.h
> >> @@ -555,7 +555,7 @@ static inline bool need_kmalloc_no_objext(void)
> >> */
> >> struct slabobj_ext {
> >> #ifdef CONFIG_MEMCG
> >> - struct obj_cgroup *objcg;
> >> + struct obj_cgroup *_objcg;
> >> #endif
> >> #ifdef CONFIG_MEM_ALLOC_PROFILING
> >> union codetag_ref ref;
> >> @@ -661,6 +661,13 @@ slab_obj_ext(struct kmem_cache *s, struct slab *slab, unsigned long obj_exts,
> >> return kasan_reset_tag(obj_ext);
> >> }
> >>
> >> +#ifdef CONFIG_MEMCG
> >> +static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ext)
> >
> > I understand why you need to return obj_cgroup** but maybe instead we
> > can have a separate setter function and just return a pointer here?
>
> Yeah I rewrote it now and it looks better. Thanks! It ended up like this due
> to some previous attempt I made.
>
> > That would also help catch cases when someone wants to set
> > obj_ext._objcg that was optimized away (for that the setter would need
> > an additional parameter to identify whether we allocated optimized
> > objext vector).
>
> It would need passing the slab parameter to assert
> slab_obj_ext_has_codetag() in debug mode. I don't think it's worth it given
> the get/set is only called from few specialized places.
Sounds good.
>
> >
> >> +{
> >> + return &obj_ext->_objcg;
> >> +}
> >> +#endif
> >> +
> >> int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
> >> gfp_t gfp, unsigned int alloc_flags);
> >>
> >> diff --git a/mm/slub.c b/mm/slub.c
> >> index 5e3f53bcd0d3..48e10198a3ce 100644
> >> --- a/mm/slub.c
> >> +++ b/mm/slub.c
> >> @@ -2523,7 +2523,7 @@ bool memcg_slab_post_charge(void *p, gfp_t flags)
> >> if (obj_exts) {
> >> get_slab_obj_exts(obj_exts);
> >> obj_ext = slab_obj_ext(s, slab, obj_exts, p);
> >> - if (unlikely(obj_ext->objcg)) {
> >> + if (unlikely(*slab_obj_ext_objcgp(obj_ext))) {
> >> put_slab_obj_exts(obj_exts);
> >> return true;
> >> }
> >>
> >> --
> >> 2.55.0
> >>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 08/12] mm/slab: change struct slabobj_ext to a union
2026-07-16 14:43 ` [PATCH RFC 08/12] mm/slab: change struct slabobj_ext to a union Vlastimil Babka (SUSE)
@ 2026-07-16 15:28 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 15:28 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Thu, Jul 16, 2026 at 7:43 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> On 7/16/26 06:11, Suren Baghdasaryan wrote:
> > On Wed, Jul 15, 2026 at 3:11 AM Vlastimil Babka (SUSE)
> > <vbabka@kernel.org> wrote:
> >> No functional change intended, the layout is still effectively static.
> >>
> >> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> >
> > This is much cleaner than what I was preparing. Nicely done!
> >
> > Reviewed-by: Suren Baghdasaryan <surenb@google.com>
>
> Thanks!
>
> >> ---
> >> mm/slab.h | 41 +++++++++++++++++++++++++++++++++--------
> >> mm/slub.c | 17 +++++++++--------
> >> 2 files changed, 42 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/mm/slab.h b/mm/slab.h
> >> index 3ad9777ad600..359ab8caf61e 100644
> >> --- a/mm/slab.h
> >> +++ b/mm/slab.h
> >> @@ -554,14 +554,34 @@ static inline bool need_kmalloc_no_objext(void)
> >> * if MEMCG_DATA_OBJEXTS is set.
> >> */
> >> struct slabobj_ext {
> >
> > Perhaps we should add a comment here stating that every element of
> > this union should be pointer-sized?
> >
>
> OK, how about this?
>
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -550,10 +550,14 @@ static inline bool need_kmalloc_no_objext(void)
> }
>
> /*
> - * Extended information for slab objects stored as an array in page->memcg_data
> - * if MEMCG_DATA_OBJEXTS is set.
> + * Extended information for slab objects stored as a pointer to an array in
> + * slab->obj_exts (aliasing page->memcg_data) if MEMCG_DATA_OBJEXTS is set.
> */
> struct slabobj_ext {
> + /*
> + * All elements of the union should be pointer-sized to avoid memory
> + * waste
> + */
Perfect. Thank you!
> union {
> #ifdef CONFIG_MEMCG
> struct obj_cgroup *_objcg;
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 12/12] mm/slab: stop allocating objcg pointers when unnecessary
2026-07-16 15:08 ` [PATCH RFC 12/12] mm/slab: stop allocating objcg pointers when unnecessary Vlastimil Babka (SUSE)
@ 2026-07-16 15:32 ` Suren Baghdasaryan
0 siblings, 0 replies; 16+ messages in thread
From: Suren Baghdasaryan @ 2026-07-16 15:32 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Harry Yoo, Hao Li, Shakeel Butt, Alexander Potapenko, Marco Elver,
Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-mm, linux-kernel, cgroups
On Thu, Jul 16, 2026 at 8:08 AM Vlastimil Babka (SUSE)
<vbabka@kernel.org> wrote:
>
> On 7/16/26 06:46, Suren Baghdasaryan wrote:
> > Maybe now we should rename static_obj_ext_size() to
> > static_obj_ext_max_size() as it reflects the max possible size of
> > slabobj_ext?
>
> Hm with _max_size() it doesn't have to be called static_ anymore?
Yeah, static_ is an implementation detail anyway.
>
> But maybe we can get rid of it completely.
>
> The only caller is calculate_sizes():
I was thinking the same but either way sounds fine to me. Keeping
obj_ext_max_size() would be a bit more self-documenting I think.
>
> #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> if (slab_args_unmergeable(args, s->flags) &&
> (aligned_size - size >= static_obj_ext_size()))
> s->flags |= SLAB_OBJ_EXT_IN_OBJ;
> #endif
>
> We don't have slab pointer to pass to static_obj_ext_max_size().
> But we should be able to figure it out from the cache via
> cache_needs_objcg().
>
> So we'd need cache_obj_ext_size()?
>
> The static max size here works, but may prevent SLAB_OBJ_EXT_IN_OBJ
> needlessly if padding can only fit codetag_ref and not objcg, but
> we don't need objcg.
> Which is probably only theoretical at this point as kmalloc_normal
> caches (that have no objcg) have no padding, at least without
> slab_debug. But still.
Maybe keep it simple as is for now and then we can optimize it further?
>
> >> + 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
> >> @@ -741,7 +749,7 @@ static inline struct obj_cgroup **slab_obj_ext_objcgp(struct slabobj_ext *obj_ex
> >> static inline union codetag_ref *
> >> slab_obj_ext_codetag_ref(struct slab *slab, struct slabobj_ext *obj_ext)
> >> {
> >> - 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 771d73abacb6..09c4931e5435 100644
> >> --- a/mm/slub.c
> >> +++ b/mm/slub.c
> >> @@ -2503,6 +2503,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);
> >>
> >> --
> >> 2.55.0
> >>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-07-16 15:33 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260715-b4-objext_split-v1-0-9a49c4ccf4c3@kernel.org>
2026-07-15 15:32 ` [PATCH RFC 00/12] mm/slab, alloc_tag: reduce obj_ext memory waste Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-1-9a49c4ccf4c3@kernel.org>
2026-07-15 16:02 ` [PATCH RFC 01/12] mm/slab: skip kfence objects in allocation profiling Suren Baghdasaryan
[not found] ` <ab9782bf-d3dd-4cb5-ae66-127b3a16330b@kernel.org>
2026-07-16 15:24 ` Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-2-9a49c4ccf4c3@kernel.org>
2026-07-15 16:13 ` [PATCH RFC 02/12] mm/slab: remove objs_per_slab() Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-3-9a49c4ccf4c3@kernel.org>
2026-07-16 0:56 ` [PATCH RFC 03/12] mm: move struct slabobj_ext to mm/slab.h Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-4-9a49c4ccf4c3@kernel.org>
2026-07-16 1:02 ` [PATCH RFC 04/12] mm/slab: make slab_obj_ext() determine object index Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-5-9a49c4ccf4c3@kernel.org>
2026-07-16 1:27 ` [PATCH RFC 05/12] mm/slab: abstract slabobj_ext.objcg access Suren Baghdasaryan
2026-07-16 13:58 ` Vlastimil Babka (SUSE)
2026-07-16 15:27 ` Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-6-9a49c4ccf4c3@kernel.org>
2026-07-16 1:28 ` [PATCH RFC 06/12] mm/slab: abstract slabobj_ext.ref access Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-7-9a49c4ccf4c3@kernel.org>
2026-07-16 1:44 ` [PATCH RFC 07/12] mm/slab: replace slab.stride with obj_exts_in_object Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-8-9a49c4ccf4c3@kernel.org>
[not found] ` <CAJuCfpGq3Yv8Dq=2mPgR5LGC=40VSNTA6mg4BjTRE0ADXMZkbg@mail.gmail.com>
2026-07-16 14:43 ` [PATCH RFC 08/12] mm/slab: change struct slabobj_ext to a union Vlastimil Babka (SUSE)
2026-07-16 15:28 ` Suren Baghdasaryan
[not found] ` <20260715-b4-objext_split-v1-9-9a49c4ccf4c3@kernel.org>
[not found] ` <CAJuCfpGkpe=5O_vW9VKqKFxrBO+QquCD+mXth_qeUSqcWcW6hA@mail.gmail.com>
2026-07-16 14:47 ` [PATCH RFC 09/12] mm/slab: introduce slab_obj_ext_has_codetag() Vlastimil Babka (SUSE)
[not found] ` <20260715-b4-objext_split-v1-12-9a49c4ccf4c3@kernel.org>
[not found] ` <CAJuCfpHuXu3BDf93zeBQWSW_k5wApegp44rHoZwk5Ym6xxbqEA@mail.gmail.com>
2026-07-16 15:08 ` [PATCH RFC 12/12] mm/slab: stop allocating objcg pointers when unnecessary Vlastimil Babka (SUSE)
2026-07-16 15:32 ` Suren Baghdasaryan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox