[PATCH RFC 11/12] mm/slab: add slab_needs_objcg() helper
From: Vlastimil Babka (SUSE)
Date: Wed Jul 15 2026 - 06:15:18 EST
Slabs of some caches never need the objcg part of struct slabobj_ext.
Introduce a helper to query this for a slab.
Currently only is_kmalloc_normal() caches are considered as not needing
objcg's. We could also consider all kmem caches without SLAB_ACCOUNT,
however some might be used with and without __GFP_ACCOUNT concurrently
and we currently don't restrict that. This can be improved later.
To make the evaluation of slab_needs_objcg() faster in the allocation
and free fast paths, add a obj_exts_needs_objcg flag into slab itself.
This optimization is only available on 64bit architectures where free
bits are available for the flag.
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>
---
mm/kfence/core.c | 3 +++
mm/slab.h | 31 +++++++++++++++++++++++++++++--
mm/slub.c | 4 ++++
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/mm/kfence/core.c b/mm/kfence/core.c
index 717e8baf7e5d..afeaf80484ad 100644
--- a/mm/kfence/core.c
+++ b/mm/kfence/core.c
@@ -640,6 +640,9 @@ static unsigned long kfence_init_pool(void)
struct slab *slab = page_slab(page);
slab->obj_exts = (unsigned long)&kfence_metadata_init[i / 2 - 1].obj_exts |
MEMCG_DATA_OBJEXTS;
+#ifdef CONFIG_64BIT
+ slab->obj_exts_needs_objcg = 1;
+#endif
#endif
}
diff --git a/mm/slab.h b/mm/slab.h
index a50347c9dbe3..948d075cdbef 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -81,10 +81,11 @@ struct freelist_counters {
#ifdef CONFIG_64BIT
/*
* Some optimizations use free bits in 'counters' field
- * to save memory. If these free bits are not available,
- * such optimizations are disabled.
+ * to save memory or CPU. If these free bits are not
+ * available, such optimizations are disabled.
*/
unsigned obj_exts_in_object:1;
+ unsigned obj_exts_needs_objcg:1;
#endif
};
};
@@ -580,6 +581,32 @@ static inline bool slab_obj_ext_has_codetag(void)
}
#endif
+#ifdef CONFIG_MEMCG
+static inline bool cache_needs_objcg(struct kmem_cache *cache)
+{
+ return !is_kmalloc_normal(cache);
+}
+
+static inline bool slab_needs_objcg(struct slab *slab)
+{
+#ifdef CONFIG_64BIT
+ return slab->obj_exts_needs_objcg;
+#else
+ return cache_needs_objcg(slab->slab_cache);
+#endif
+}
+#else
+static inline bool cache_needs_objcg(struct kmem_cache *cache)
+{
+ return false;
+}
+
+static inline bool slab_needs_objcg(struct slab *slab)
+{
+ return false;
+}
+#endif
+
static inline size_t static_obj_ext_size(void)
{
size_t sz = 0;
diff --git a/mm/slub.c b/mm/slub.c
index 4200e7105b30..771d73abacb6 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3426,6 +3426,10 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags,
slab->objects = oo_objects(oo);
+#ifdef CONFIG_64BIT
+ if (cache_needs_objcg(s))
+ slab->obj_exts_needs_objcg = 1;
+#endif
slab->slab_cache = s;
kasan_poison_slab(slab);
--
2.55.0