From: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>
To: Harry Yoo <harry@kernel.org>, Suren Baghdasaryan <surenb@google.com>
Cc: Hao Li <hao.li@linux.dev>, Shakeel Butt <shakeel.butt@linux.dev>,
Alexander Potapenko <glider@google.com>,
Marco Elver <elver@google.com>,
Andrew Morton <akpm@linux-foundation.org>,
Christoph Lameter <cl@gentwo.org>,
David Rientjes <rientjes@google.com>,
Roman Gushchin <roman.gushchin@linux.dev>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
cgroups@vger.kernel.org,
"Vlastimil Babka (SUSE)" <vbabka@kernel.org>
Subject: [PATCH v3 07/13] mm/slab: replace slab.stride with obj_exts_in_object
Date: Mon, 27 Jul 2026 14:54:01 +0200 [thread overview]
Message-ID: <20260727-b4-objext_split-v3-7-c29ef0f1f257@kernel.org> (raw)
In-Reply-To: <20260727-b4-objext_split-v3-0-c29ef0f1f257@kernel.org>
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.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Hao Li <hao.li@linux.dev>
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
---
mm/slab.h | 44 +++++++++++++++++++++++++-------------------
mm/slub.c | 42 ++++++++++++++++--------------------------
2 files changed, 41 insertions(+), 45 deletions(-)
diff --git a/mm/slab.h b/mm/slab.h
index 562b62802561..79c758001f98 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
@@ -657,8 +655,15 @@ 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);
}
@@ -700,9 +705,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 7812a7c097c9..f6ec3618dd1c 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);
@@ -2256,9 +2248,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;
@@ -2292,7 +2281,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);
}
}
@@ -3405,9 +3394,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;
@@ -6540,7 +6530,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
next prev parent reply other threads:[~2026-07-27 12:54 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 12:53 [PATCH v3 00/13] mm/slab, alloc_tag: reduce obj_ext memory waste Vlastimil Babka (SUSE)
2026-07-27 12:53 ` [PATCH v3 01/13] mm/slab: skip kfence objects in allocation profiling Vlastimil Babka (SUSE)
2026-07-27 12:53 ` [PATCH v3 02/13] mm/slab: remove objs_per_slab() Vlastimil Babka (SUSE)
2026-07-27 12:53 ` [PATCH v3 03/13] mm: move struct slabobj_ext to mm/slab.h Vlastimil Babka (SUSE)
2026-07-27 12:53 ` [PATCH v3 04/13] mm/slab: make slab_obj_ext() determine object index Vlastimil Babka (SUSE)
2026-07-27 12:53 ` [PATCH v3 05/13] mm/slab: abstract slabobj_ext.objcg access Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 06/13] mm/slab: abstract slabobj_ext.ref access Vlastimil Babka (SUSE)
2026-07-27 12:54 ` Vlastimil Babka (SUSE) [this message]
2026-07-27 12:54 ` [PATCH v3 08/13] mm/slab: change struct slabobj_ext to a union Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 09/13] mm/slab: introduce slab_obj_ext_has_codetag() Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 10/13] mm/slab: reduce slabobj_ext memory with allocation profiling disabled Vlastimil Babka (SUSE)
2026-07-27 14:07 ` Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 11/13] mm/slab: add cache_ and slab_needs_objcg() helpers Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 12/13] mm/slab: stop allocating objcg pointers when unnecessary Vlastimil Babka (SUSE)
2026-07-27 12:54 ` [PATCH v3 13/13] mm/slab, kfence, memcg: completely remove obj_ext for kfence objects Vlastimil Babka (SUSE)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260727-b4-objext_split-v3-7-c29ef0f1f257@kernel.org \
--to=vbabka@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=cgroups@vger.kernel.org \
--cc=cl@gentwo.org \
--cc=elver@google.com \
--cc=glider@google.com \
--cc=hao.li@linux.dev \
--cc=harry@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.