* [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable()
2026-01-27 10:31 [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
@ 2026-01-27 10:31 ` Harry Yoo
2026-01-27 16:35 ` Vlastimil Babka
2026-01-27 10:31 ` [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Harry Yoo @ 2026-01-27 10:31 UTC (permalink / raw)
To: Andrew Morton, Vlastimil Babka
Cc: Christoph Lameter, David Rientjes, Roman Gushchin, Muchun Song,
Shakeel Butt, Michal Hocko, Yeoreum Yun, Johannes Weiner,
Suren Baghdasaryan, Harry Yoo, Hai Li, linux-mm
slab_mergeable() determines whether a slab cache can be merged, but it
should not be used when the cache is not fully created yet.
Extract the pre-cache-creation mergeability checks into
slab_args_unmergeable(), which evaluates kmem_cache_args, slab flags,
and slab_nomerge to determine if a cache will be mergeable before it is
created.
Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
---
mm/slab_common.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 2e80d323f550..904414c3ebb8 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -174,24 +174,32 @@ int slab_unmergeable(struct kmem_cache *s)
return 0;
}
-static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
- const char *name, struct kmem_cache_args *args)
+static bool slab_args_unmergeable(struct kmem_cache_args *args,
+ slab_flags_t flags)
{
- struct kmem_cache *s;
- unsigned int align;
-
if (slab_nomerge)
- return NULL;
+ return true;
if (args->ctor)
- return NULL;
+ return true;
if (IS_ENABLED(CONFIG_HARDENED_USERCOPY) && args->usersize)
- return NULL;
-
- flags = kmem_cache_flags(flags, name);
+ return true;
if (flags & SLAB_NEVER_MERGE)
+ return true;
+
+ return false;
+}
+
+static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
+ const char *name, struct kmem_cache_args *args)
+{
+ struct kmem_cache *s;
+ unsigned int align;
+
+ flags = kmem_cache_flags(flags, name);
+ if (slab_args_unmergeable(args, flags))
return NULL;
size = ALIGN(size, sizeof(void *));
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable()
2026-01-27 10:31 ` [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable() Harry Yoo
@ 2026-01-27 16:35 ` Vlastimil Babka
2026-01-27 16:42 ` Harry Yoo
0 siblings, 1 reply; 14+ messages in thread
From: Vlastimil Babka @ 2026-01-27 16:35 UTC (permalink / raw)
To: Harry Yoo, Andrew Morton
Cc: Christoph Lameter, David Rientjes, Roman Gushchin, Muchun Song,
Shakeel Butt, Michal Hocko, Yeoreum Yun, Johannes Weiner,
Suren Baghdasaryan, Hai Li, linux-mm
On 1/27/26 11:31, Harry Yoo wrote:
> slab_mergeable() determines whether a slab cache can be merged, but it
> should not be used when the cache is not fully created yet.
>
> Extract the pre-cache-creation mergeability checks into
> slab_args_unmergeable(), which evaluates kmem_cache_args, slab flags,
> and slab_nomerge to determine if a cache will be mergeable before it is
> created.
>
> Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
> ---
> mm/slab_common.c | 28 ++++++++++++++++++----------
> 1 file changed, 18 insertions(+), 10 deletions(-)
>
> diff --git a/mm/slab_common.c b/mm/slab_common.c
> index 2e80d323f550..904414c3ebb8 100644
> --- a/mm/slab_common.c
> +++ b/mm/slab_common.c
> @@ -174,24 +174,32 @@ int slab_unmergeable(struct kmem_cache *s)
> return 0;
> }
>
> -static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
> - const char *name, struct kmem_cache_args *args)
> +static bool slab_args_unmergeable(struct kmem_cache_args *args,
> + slab_flags_t flags)
> {
> - struct kmem_cache *s;
> - unsigned int align;
> -
> if (slab_nomerge)
> - return NULL;
> + return true;
I think this still logically belongs to find_mergeable() and not here, so
moved there. Agreed?
> if (args->ctor)
> - return NULL;
> + return true;
>
> if (IS_ENABLED(CONFIG_HARDENED_USERCOPY) && args->usersize)
> - return NULL;
> -
> - flags = kmem_cache_flags(flags, name);
> + return true;
>
> if (flags & SLAB_NEVER_MERGE)
> + return true;
> +
> + return false;
> +}
> +
> +static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
> + const char *name, struct kmem_cache_args *args)
> +{
> + struct kmem_cache *s;
> + unsigned int align;
> +
> + flags = kmem_cache_flags(flags, name);
> + if (slab_args_unmergeable(args, flags))
> return NULL;
>
> size = ALIGN(size, sizeof(void *));
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable()
2026-01-27 16:35 ` Vlastimil Babka
@ 2026-01-27 16:42 ` Harry Yoo
2026-01-27 16:49 ` Vlastimil Babka
0 siblings, 1 reply; 14+ messages in thread
From: Harry Yoo @ 2026-01-27 16:42 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
Muchun Song, Shakeel Butt, Michal Hocko, Yeoreum Yun,
Johannes Weiner, Suren Baghdasaryan, Hai Li, linux-mm
On Tue, Jan 27, 2026 at 05:35:50PM +0100, Vlastimil Babka wrote:
> On 1/27/26 11:31, Harry Yoo wrote:
> > slab_mergeable() determines whether a slab cache can be merged, but it
> > should not be used when the cache is not fully created yet.
> >
> > Extract the pre-cache-creation mergeability checks into
> > slab_args_unmergeable(), which evaluates kmem_cache_args, slab flags,
> > and slab_nomerge to determine if a cache will be mergeable before it is
> > created.
> >
> > Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
> > ---
> > mm/slab_common.c | 28 ++++++++++++++++++----------
> > 1 file changed, 18 insertions(+), 10 deletions(-)
> >
> > diff --git a/mm/slab_common.c b/mm/slab_common.c
> > index 2e80d323f550..904414c3ebb8 100644
> > --- a/mm/slab_common.c
> > +++ b/mm/slab_common.c
> > @@ -174,24 +174,32 @@ int slab_unmergeable(struct kmem_cache *s)
> > return 0;
> > }
> >
> > -static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
> > - const char *name, struct kmem_cache_args *args)
> > +static bool slab_args_unmergeable(struct kmem_cache_args *args,
> > + slab_flags_t flags)
> > {
> > - struct kmem_cache *s;
> > - unsigned int align;
> > -
> > if (slab_nomerge)
> > - return NULL;
> > + return true;
>
> I think this still logically belongs to find_mergeable() and not here, so
> moved there. Agreed?
But then patch 2/2 should be modified to check slab_nomerge then?
And even slab_unmergeable() does slab_nomerge check, so perhaps it's
more consistent to do it in slab_args_unmergeable().
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable()
2026-01-27 16:42 ` Harry Yoo
@ 2026-01-27 16:49 ` Vlastimil Babka
0 siblings, 0 replies; 14+ messages in thread
From: Vlastimil Babka @ 2026-01-27 16:49 UTC (permalink / raw)
To: Harry Yoo
Cc: Andrew Morton, Christoph Lameter, David Rientjes, Roman Gushchin,
Muchun Song, Shakeel Butt, Michal Hocko, Yeoreum Yun,
Johannes Weiner, Suren Baghdasaryan, Hai Li, linux-mm
On 1/27/26 17:42, Harry Yoo wrote:
> On Tue, Jan 27, 2026 at 05:35:50PM +0100, Vlastimil Babka wrote:
>> On 1/27/26 11:31, Harry Yoo wrote:
>> > slab_mergeable() determines whether a slab cache can be merged, but it
>> > should not be used when the cache is not fully created yet.
>> >
>> > Extract the pre-cache-creation mergeability checks into
>> > slab_args_unmergeable(), which evaluates kmem_cache_args, slab flags,
>> > and slab_nomerge to determine if a cache will be mergeable before it is
>> > created.
>> >
>> > Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
>> > ---
>> > mm/slab_common.c | 28 ++++++++++++++++++----------
>> > 1 file changed, 18 insertions(+), 10 deletions(-)
>> >
>> > diff --git a/mm/slab_common.c b/mm/slab_common.c
>> > index 2e80d323f550..904414c3ebb8 100644
>> > --- a/mm/slab_common.c
>> > +++ b/mm/slab_common.c
>> > @@ -174,24 +174,32 @@ int slab_unmergeable(struct kmem_cache *s)
>> > return 0;
>> > }
>> >
>> > -static struct kmem_cache *find_mergeable(unsigned int size, slab_flags_t flags,
>> > - const char *name, struct kmem_cache_args *args)
>> > +static bool slab_args_unmergeable(struct kmem_cache_args *args,
>> > + slab_flags_t flags)
>> > {
>> > - struct kmem_cache *s;
>> > - unsigned int align;
>> > -
>> > if (slab_nomerge)
>> > - return NULL;
>> > + return true;
>>
>> I think this still logically belongs to find_mergeable() and not here, so
>> moved there. Agreed?
>
> But then patch 2/2 should be modified to check slab_nomerge then?
Yeah I would do that as well,
> And even slab_unmergeable() does slab_nomerge check, so perhaps it's
> more consistent to do it in slab_args_unmergeable().
But this is true so I'll leave both as you did, thanks!
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-01-27 10:31 [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
2026-01-27 10:31 ` [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable() Harry Yoo
@ 2026-01-27 10:31 ` Harry Yoo
2026-02-03 11:56 ` Hao Li
2026-01-27 17:06 ` [PATCH V1 0/2] Only " Vlastimil Babka
2026-01-27 18:21 ` Johannes Weiner
3 siblings, 1 reply; 14+ messages in thread
From: Harry Yoo @ 2026-01-27 10:31 UTC (permalink / raw)
To: Andrew Morton, Vlastimil Babka
Cc: Christoph Lameter, David Rientjes, Roman Gushchin, Muchun Song,
Shakeel Butt, Michal Hocko, Yeoreum Yun, Johannes Weiner,
Suren Baghdasaryan, Harry Yoo, Hai Li, linux-mm
While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
slab objects, it prevents slab merging because merging can change
the metadata layout.
As pointed out Vlastimil Babka, disabling merging solely for this memory
optimization may not be a net win, because disabling slab merging tends
to increase overall memory usage.
Restrict SLAB_OBJ_EXT_IN_OBJ to caches that are already unmergeable for
other reasons (e.g., those with constructors or SLAB_TYPESAFE_BY_RCU).
Suggested-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
---
mm/slab.h | 1 +
mm/slab_common.c | 3 +--
mm/slub.c | 3 ++-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/mm/slab.h b/mm/slab.h
index 8593c506cbf1..a5c4f981ee8b 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -388,6 +388,7 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,
unsigned int useroffset, unsigned int usersize);
int slab_unmergeable(struct kmem_cache *s);
+bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags);
slab_flags_t kmem_cache_flags(slab_flags_t flags, const char *name);
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 904414c3ebb8..d5a70a831a2a 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -174,8 +174,7 @@ int slab_unmergeable(struct kmem_cache *s)
return 0;
}
-static bool slab_args_unmergeable(struct kmem_cache_args *args,
- slab_flags_t flags)
+bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
{
if (slab_nomerge)
return true;
diff --git a/mm/slub.c b/mm/slub.c
index ae9af184a18b..0581847e7dac 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
*/
aligned_size = ALIGN(size, s->align);
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
- if (aligned_size - size >= sizeof(struct slabobj_ext))
+ if (slab_args_unmergeable(args, s->flags) &&
+ (aligned_size - size >= sizeof(struct slabobj_ext)))
s->flags |= SLAB_OBJ_EXT_IN_OBJ;
#endif
size = aligned_size;
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-01-27 10:31 ` [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
@ 2026-02-03 11:56 ` Hao Li
2026-02-03 12:32 ` Harry Yoo
0 siblings, 1 reply; 14+ messages in thread
From: Hao Li @ 2026-02-03 11:56 UTC (permalink / raw)
To: Harry Yoo
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Johannes Weiner, Suren Baghdasaryan,
linux-mm
On Tue, Jan 27, 2026 at 07:31:51PM +0900, Harry Yoo wrote:
> While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> slab objects, it prevents slab merging because merging can change
> the metadata layout.
>
> As pointed out Vlastimil Babka, disabling merging solely for this memory
> optimization may not be a net win, because disabling slab merging tends
> to increase overall memory usage.
>
> Restrict SLAB_OBJ_EXT_IN_OBJ to caches that are already unmergeable for
> other reasons (e.g., those with constructors or SLAB_TYPESAFE_BY_RCU).
>
> Suggested-by: Vlastimil Babka <vbabka@suse.cz>
> Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
> ---
> mm/slab.h | 1 +
> mm/slab_common.c | 3 +--
> mm/slub.c | 3 ++-
> 3 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/mm/slab.h b/mm/slab.h
> index 8593c506cbf1..a5c4f981ee8b 100644
> --- a/mm/slab.h
> +++ b/mm/slab.h
> @@ -388,6 +388,7 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,
> unsigned int useroffset, unsigned int usersize);
>
> int slab_unmergeable(struct kmem_cache *s);
> +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags);
>
> slab_flags_t kmem_cache_flags(slab_flags_t flags, const char *name);
>
> diff --git a/mm/slab_common.c b/mm/slab_common.c
> index 904414c3ebb8..d5a70a831a2a 100644
> --- a/mm/slab_common.c
> +++ b/mm/slab_common.c
> @@ -174,8 +174,7 @@ int slab_unmergeable(struct kmem_cache *s)
> return 0;
> }
>
> -static bool slab_args_unmergeable(struct kmem_cache_args *args,
> - slab_flags_t flags)
> +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
> {
> if (slab_nomerge)
> return true;
> diff --git a/mm/slub.c b/mm/slub.c
> index ae9af184a18b..0581847e7dac 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
> */
> aligned_size = ALIGN(size, s->align);
> #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> - if (aligned_size - size >= sizeof(struct slabobj_ext))
> + if (slab_args_unmergeable(args, s->flags) &&
> + (aligned_size - size >= sizeof(struct slabobj_ext)))
> s->flags |= SLAB_OBJ_EXT_IN_OBJ;
Hi Harry,
This patch looks reasonable to me. I just noticed a minor point that I
wanted to bring up:
It seems a bit self-referential that SLAB_NEVER_MERGE already includes
SLAB_OBJ_EXT_IN_OBJ, but we're using SLAB_NEVER_MERGE to decide whether to set
SLAB_OBJ_EXT_IN_OBJ.
Do you think it might be helpful to add a comment here for better clarity?
--
Thanks,
Hao
> #endif
> size = aligned_size;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-02-03 11:56 ` Hao Li
@ 2026-02-03 12:32 ` Harry Yoo
2026-02-04 0:45 ` Hao Li
0 siblings, 1 reply; 14+ messages in thread
From: Harry Yoo @ 2026-02-03 12:32 UTC (permalink / raw)
To: Hao Li
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Johannes Weiner, Suren Baghdasaryan,
linux-mm
On Tue, Feb 03, 2026 at 07:56:16PM +0800, Hao Li wrote:
> On Tue, Jan 27, 2026 at 07:31:51PM +0900, Harry Yoo wrote:
> > While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> > slab objects, it prevents slab merging because merging can change
> > the metadata layout.
> >
> > As pointed out Vlastimil Babka, disabling merging solely for this memory
> > optimization may not be a net win, because disabling slab merging tends
> > to increase overall memory usage.
> >
> > Restrict SLAB_OBJ_EXT_IN_OBJ to caches that are already unmergeable for
> > other reasons (e.g., those with constructors or SLAB_TYPESAFE_BY_RCU).
> >
> > Suggested-by: Vlastimil Babka <vbabka@suse.cz>
> > Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
> > ---
> > mm/slab.h | 1 +
> > mm/slab_common.c | 3 +--
> > mm/slub.c | 3 ++-
> > 3 files changed, 4 insertions(+), 3 deletions(-)
> >
> > diff --git a/mm/slab.h b/mm/slab.h
> > index 8593c506cbf1..a5c4f981ee8b 100644
> > --- a/mm/slab.h
> > +++ b/mm/slab.h
> > @@ -388,6 +388,7 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,
> > unsigned int useroffset, unsigned int usersize);
> >
> > int slab_unmergeable(struct kmem_cache *s);
> > +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags);
> >
> > slab_flags_t kmem_cache_flags(slab_flags_t flags, const char *name);
> >
> > diff --git a/mm/slab_common.c b/mm/slab_common.c
> > index 904414c3ebb8..d5a70a831a2a 100644
> > --- a/mm/slab_common.c
> > +++ b/mm/slab_common.c
> > @@ -174,8 +174,7 @@ int slab_unmergeable(struct kmem_cache *s)
> > return 0;
> > }
> >
> > -static bool slab_args_unmergeable(struct kmem_cache_args *args,
> > - slab_flags_t flags)
> > +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
> > {
> > if (slab_nomerge)
> > return true;
> > diff --git a/mm/slub.c b/mm/slub.c
> > index ae9af184a18b..0581847e7dac 100644
> > --- a/mm/slub.c
> > +++ b/mm/slub.c
> > @@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
> > */
> > aligned_size = ALIGN(size, s->align);
> > #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> > - if (aligned_size - size >= sizeof(struct slabobj_ext))
> > + if (slab_args_unmergeable(args, s->flags) &&
> > + (aligned_size - size >= sizeof(struct slabobj_ext)))
> > s->flags |= SLAB_OBJ_EXT_IN_OBJ;
>
> Hi Harry,
>
> This patch looks reasonable to me. I just noticed a minor point that I
> wanted to bring up:
>
> It seems a bit self-referential that SLAB_NEVER_MERGE already includes
> SLAB_OBJ_EXT_IN_OBJ, but we're using SLAB_NEVER_MERGE to decide whether to set
> SLAB_OBJ_EXT_IN_OBJ.
Hi Hao, thanks for bringing it up!
> Do you think it might be helpful to add a comment here for better clarity?
Hmm but I'm not sure what should be clarified here.
(perhaps because I wrote it).
Checking SLAB_OBJ_EXT_IN_OBJ (as part of SLAB_NEVER_MERGE) before
setting SLAB_OBJ_EXT_IN_OBJ should be fine (because it's not set before
we set it), and once you set it, it should prevent merging.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-02-03 12:32 ` Harry Yoo
@ 2026-02-04 0:45 ` Hao Li
2026-02-05 5:13 ` Harry Yoo
0 siblings, 1 reply; 14+ messages in thread
From: Hao Li @ 2026-02-04 0:45 UTC (permalink / raw)
To: Harry Yoo
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Johannes Weiner, Suren Baghdasaryan,
linux-mm
On Tue, Feb 03, 2026 at 09:32:06PM +0900, Harry Yoo wrote:
> On Tue, Feb 03, 2026 at 07:56:16PM +0800, Hao Li wrote:
> > On Tue, Jan 27, 2026 at 07:31:51PM +0900, Harry Yoo wrote:
> > > While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> > > slab objects, it prevents slab merging because merging can change
> > > the metadata layout.
> > >
> > > As pointed out Vlastimil Babka, disabling merging solely for this memory
> > > optimization may not be a net win, because disabling slab merging tends
> > > to increase overall memory usage.
> > >
> > > Restrict SLAB_OBJ_EXT_IN_OBJ to caches that are already unmergeable for
> > > other reasons (e.g., those with constructors or SLAB_TYPESAFE_BY_RCU).
> > >
> > > Suggested-by: Vlastimil Babka <vbabka@suse.cz>
> > > Signed-off-by: Harry Yoo <harry.yoo@oracle.com>
> > > ---
> > > mm/slab.h | 1 +
> > > mm/slab_common.c | 3 +--
> > > mm/slub.c | 3 ++-
> > > 3 files changed, 4 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/mm/slab.h b/mm/slab.h
> > > index 8593c506cbf1..a5c4f981ee8b 100644
> > > --- a/mm/slab.h
> > > +++ b/mm/slab.h
> > > @@ -388,6 +388,7 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,
> > > unsigned int useroffset, unsigned int usersize);
> > >
> > > int slab_unmergeable(struct kmem_cache *s);
> > > +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags);
> > >
> > > slab_flags_t kmem_cache_flags(slab_flags_t flags, const char *name);
> > >
> > > diff --git a/mm/slab_common.c b/mm/slab_common.c
> > > index 904414c3ebb8..d5a70a831a2a 100644
> > > --- a/mm/slab_common.c
> > > +++ b/mm/slab_common.c
> > > @@ -174,8 +174,7 @@ int slab_unmergeable(struct kmem_cache *s)
> > > return 0;
> > > }
> > >
> > > -static bool slab_args_unmergeable(struct kmem_cache_args *args,
> > > - slab_flags_t flags)
> > > +bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
> > > {
> > > if (slab_nomerge)
> > > return true;
> > > diff --git a/mm/slub.c b/mm/slub.c
> > > index ae9af184a18b..0581847e7dac 100644
> > > --- a/mm/slub.c
> > > +++ b/mm/slub.c
> > > @@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
> > > */
> > > aligned_size = ALIGN(size, s->align);
> > > #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> > > - if (aligned_size - size >= sizeof(struct slabobj_ext))
> > > + if (slab_args_unmergeable(args, s->flags) &&
> > > + (aligned_size - size >= sizeof(struct slabobj_ext)))
> > > s->flags |= SLAB_OBJ_EXT_IN_OBJ;
> >
> > Hi Harry,
> >
> > This patch looks reasonable to me. I just noticed a minor point that I
> > wanted to bring up:
> >
> > It seems a bit self-referential that SLAB_NEVER_MERGE already includes
> > SLAB_OBJ_EXT_IN_OBJ, but we're using SLAB_NEVER_MERGE to decide whether to set
> > SLAB_OBJ_EXT_IN_OBJ.
>
> Hi Hao, thanks for bringing it up!
>
> > Do you think it might be helpful to add a comment here for better clarity?
>
> Hmm but I'm not sure what should be clarified here.
> (perhaps because I wrote it).
>
> Checking SLAB_OBJ_EXT_IN_OBJ (as part of SLAB_NEVER_MERGE) before
> setting SLAB_OBJ_EXT_IN_OBJ should be fine (because it's not set before
> we set it), and once you set it, it should prevent merging.
Yeah, s->flags currently doesn't have SLAB_OBJ_EXT_IN_OBJ, and the functionality
here is totally fine. I just happened to notice this while reading through the
code, and from a semantic perspective, it made me pause for a moment. It looks
like we're checking if s->flags contains SLAB_OBJ_EXT_IN_OBJ (among other flags)
to decide whether we can set SLAB_OBJ_EXT_IN_OBJ. Maybe we could add a small
comment like: "SLAB_OBJ_EXT_IN_OBJ hasn't been set yet here; this is just
checking for other unmergeable reasons."
Of course, this is just a small thought, it's perfectly fine to leave it as is-I
just thought it might help slightly.
--
Thanks,
Hao
>
> --
> Cheers,
> Harry / Hyeonggon
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-02-04 0:45 ` Hao Li
@ 2026-02-05 5:13 ` Harry Yoo
2026-02-05 6:27 ` Hao Li
0 siblings, 1 reply; 14+ messages in thread
From: Harry Yoo @ 2026-02-05 5:13 UTC (permalink / raw)
To: Hao Li
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Johannes Weiner, Suren Baghdasaryan,
linux-mm
On Wed, Feb 04, 2026 at 08:45:19AM +0800, Hao Li wrote:
> On Tue, Feb 03, 2026 at 09:32:06PM +0900, Harry Yoo wrote:
> > On Tue, Feb 03, 2026 at 07:56:16PM +0800, Hao Li wrote:
> > > On Tue, Jan 27, 2026 at 07:31:51PM +0900, Harry Yoo wrote:
> > > > diff --git a/mm/slub.c b/mm/slub.c
> > > > index ae9af184a18b..0581847e7dac 100644
> > > > --- a/mm/slub.c
> > > > +++ b/mm/slub.c
> > > > @@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
> > > > */
> > > > aligned_size = ALIGN(size, s->align);
> > > > #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> > > > - if (aligned_size - size >= sizeof(struct slabobj_ext))
> > > > + if (slab_args_unmergeable(args, s->flags) &&
> > > > + (aligned_size - size >= sizeof(struct slabobj_ext)))
> > > > s->flags |= SLAB_OBJ_EXT_IN_OBJ;
> > >
> > > Hi Harry,
> > >
> > > This patch looks reasonable to me. I just noticed a minor point that I
> > > wanted to bring up:
> > >
> > > It seems a bit self-referential that SLAB_NEVER_MERGE already includes
> > > SLAB_OBJ_EXT_IN_OBJ, but we're using SLAB_NEVER_MERGE to decide whether to set
> > > SLAB_OBJ_EXT_IN_OBJ.
> >
> > Hi Hao, thanks for bringing it up!
> >
> > > Do you think it might be helpful to add a comment here for better clarity?
> >
> > Hmm but I'm not sure what should be clarified here.
> > (perhaps because I wrote it).
> >
> > Checking SLAB_OBJ_EXT_IN_OBJ (as part of SLAB_NEVER_MERGE) before
> > setting SLAB_OBJ_EXT_IN_OBJ should be fine (because it's not set before
> > we set it), and once you set it, it should prevent merging.
>
> Yeah, s->flags currently doesn't have SLAB_OBJ_EXT_IN_OBJ, and the functionality
> here is totally fine. I just happened to notice this while reading through the
> code, and from a semantic perspective, it made me pause for a moment. It looks
> like we're checking if s->flags contains SLAB_OBJ_EXT_IN_OBJ (among other flags)
> to decide whether we can set SLAB_OBJ_EXT_IN_OBJ. Maybe we could add a small
> comment like: "SLAB_OBJ_EXT_IN_OBJ hasn't been set yet here; this is just
> checking for other unmergeable reasons."
>
> Of course, this is just a small thought, it's perfectly fine to leave it as is-I
> just thought it might help slightly.
I think it's probably okay to leave it as-is for now.
But thanks for bringing this up!
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-02-05 5:13 ` Harry Yoo
@ 2026-02-05 6:27 ` Hao Li
0 siblings, 0 replies; 14+ messages in thread
From: Hao Li @ 2026-02-05 6:27 UTC (permalink / raw)
To: Harry Yoo
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Johannes Weiner, Suren Baghdasaryan,
linux-mm
On Thu, Feb 05, 2026 at 02:13:23PM +0900, Harry Yoo wrote:
> On Wed, Feb 04, 2026 at 08:45:19AM +0800, Hao Li wrote:
> > On Tue, Feb 03, 2026 at 09:32:06PM +0900, Harry Yoo wrote:
> > > On Tue, Feb 03, 2026 at 07:56:16PM +0800, Hao Li wrote:
> > > > On Tue, Jan 27, 2026 at 07:31:51PM +0900, Harry Yoo wrote:
> > > > > diff --git a/mm/slub.c b/mm/slub.c
> > > > > index ae9af184a18b..0581847e7dac 100644
> > > > > --- a/mm/slub.c
> > > > > +++ b/mm/slub.c
> > > > > @@ -7676,7 +7676,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
> > > > > */
> > > > > aligned_size = ALIGN(size, s->align);
> > > > > #if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
> > > > > - if (aligned_size - size >= sizeof(struct slabobj_ext))
> > > > > + if (slab_args_unmergeable(args, s->flags) &&
> > > > > + (aligned_size - size >= sizeof(struct slabobj_ext)))
> > > > > s->flags |= SLAB_OBJ_EXT_IN_OBJ;
> > > >
> > > > Hi Harry,
> > > >
> > > > This patch looks reasonable to me. I just noticed a minor point that I
> > > > wanted to bring up:
> > > >
> > > > It seems a bit self-referential that SLAB_NEVER_MERGE already includes
> > > > SLAB_OBJ_EXT_IN_OBJ, but we're using SLAB_NEVER_MERGE to decide whether to set
> > > > SLAB_OBJ_EXT_IN_OBJ.
> > >
> > > Hi Hao, thanks for bringing it up!
> > >
> > > > Do you think it might be helpful to add a comment here for better clarity?
> > >
> > > Hmm but I'm not sure what should be clarified here.
> > > (perhaps because I wrote it).
> > >
> > > Checking SLAB_OBJ_EXT_IN_OBJ (as part of SLAB_NEVER_MERGE) before
> > > setting SLAB_OBJ_EXT_IN_OBJ should be fine (because it's not set before
> > > we set it), and once you set it, it should prevent merging.
> >
> > Yeah, s->flags currently doesn't have SLAB_OBJ_EXT_IN_OBJ, and the functionality
> > here is totally fine. I just happened to notice this while reading through the
> > code, and from a semantic perspective, it made me pause for a moment. It looks
> > like we're checking if s->flags contains SLAB_OBJ_EXT_IN_OBJ (among other flags)
> > to decide whether we can set SLAB_OBJ_EXT_IN_OBJ. Maybe we could add a small
> > comment like: "SLAB_OBJ_EXT_IN_OBJ hasn't been set yet here; this is just
> > checking for other unmergeable reasons."
> >
> > Of course, this is just a small thought, it's perfectly fine to leave it as is-I
> > just thought it might help slightly.
>
> I think it's probably okay to leave it as-is for now.
> But thanks for bringing this up!
>
Ah, no problem, thanks!
--
Thanks,
Hao
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-01-27 10:31 [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
2026-01-27 10:31 ` [PATCH V1 1/2] mm/slab: factor out slab_args_unmergeable() Harry Yoo
2026-01-27 10:31 ` [PATCH V1 2/2] mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
@ 2026-01-27 17:06 ` Vlastimil Babka
2026-01-27 18:21 ` Johannes Weiner
3 siblings, 0 replies; 14+ messages in thread
From: Vlastimil Babka @ 2026-01-27 17:06 UTC (permalink / raw)
To: Harry Yoo, Andrew Morton
Cc: Christoph Lameter, David Rientjes, Roman Gushchin, Muchun Song,
Shakeel Butt, Michal Hocko, Yeoreum Yun, Johannes Weiner,
Suren Baghdasaryan, Hai Li, linux-mm
On 1/27/26 11:31, Harry Yoo wrote:
> While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> slab objects, it prevents slab merging because merging can change
> the metadata layout.
>
> As pointed out Vlastimil Babka, disabling merging solely for this memory
> optimization may not be a net win, because disabling slab merging tends
> to increase overall memory usage.
>
> So let's take a conservative approach and restrict SLAB_OBJ_EXT_IN_OBJ
> to caches that are already unmergeable for other reasons.
>
> Ideally this should be part of the slab/for-7.0/obj_metadata branch,
> but due to a conflict with slab/for-7.0/sheaves, I based it on
> slab/for-next (be36abd97e52).
>
> Patch 1 factors out mergeability logic to slab_args_unmergeable().
> This is used to determine mergeability before the cache is created.
>
> Patch 2 uses the new function to allow SLAB_OBJ_EXT_IN_OBJ
> only when merging is not allowed for other reasons.
>
> Harry Yoo (2):
> mm/slab: factor out slab_args_unmergeable()
> mm/slab: only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
Thanks, applied to slab/for-next and reorganized the sub-branches a bit to
prevent conflicts.
> mm/slab.h | 1 +
> mm/slab_common.c | 27 +++++++++++++++++----------
> mm/slub.c | 3 ++-
> 3 files changed, 20 insertions(+), 11 deletions(-)
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches
2026-01-27 10:31 [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches Harry Yoo
` (2 preceding siblings ...)
2026-01-27 17:06 ` [PATCH V1 0/2] Only " Vlastimil Babka
@ 2026-01-27 18:21 ` Johannes Weiner
2026-01-28 3:09 ` To enable, or not to enable slab merging? That is the question (was: Re: [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches) Harry Yoo
3 siblings, 1 reply; 14+ messages in thread
From: Johannes Weiner @ 2026-01-27 18:21 UTC (permalink / raw)
To: Harry Yoo
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Suren Baghdasaryan, Hai Li, linux-mm
On Tue, Jan 27, 2026 at 07:31:49PM +0900, Harry Yoo wrote:
> While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> slab objects, it prevents slab merging because merging can change
> the metadata layout.
>
> As pointed out Vlastimil Babka, disabling merging solely for this memory
> optimization may not be a net win, because disabling slab merging tends
> to increase overall memory usage.
Is this motivated by a production issue or a more a correctness thing?
It's somewhat tangential, but we've had practical problems with slab
merging and ended up disabling it in the Meta fleet. It makes it
difficult to identify culprits when there is a footprint regression in
merged caches. IIRC there was at least one instance where it merged
wildly different lifetimes, which raises fragmentation concerns. In
the end we turned it off and noted no meaningful usage difference.
So I'm curious if there are cases where it tangibly helps. And I
wonder whether default y makes sense given its observability and
predictability implications.
^ permalink raw reply [flat|nested] 14+ messages in thread* To enable, or not to enable slab merging? That is the question (was: Re: [PATCH V1 0/2] Only allow SLAB_OBJ_EXT_IN_OBJ for unmergeable caches)
2026-01-27 18:21 ` Johannes Weiner
@ 2026-01-28 3:09 ` Harry Yoo
0 siblings, 0 replies; 14+ messages in thread
From: Harry Yoo @ 2026-01-28 3:09 UTC (permalink / raw)
To: Johannes Weiner
Cc: Andrew Morton, Vlastimil Babka, Christoph Lameter,
David Rientjes, Roman Gushchin, Muchun Song, Shakeel Butt,
Michal Hocko, Yeoreum Yun, Suren Baghdasaryan, Hai Li, linux-mm
On Tue, Jan 27, 2026 at 01:21:09PM -0500, Johannes Weiner wrote:
> On Tue, Jan 27, 2026 at 07:31:49PM +0900, Harry Yoo wrote:
> > While SLAB_OBJ_EXT_IN_OBJ allows to reduce memory overhead to account
> > slab objects, it prevents slab merging because merging can change
> > the metadata layout.
> >
> > As pointed out Vlastimil Babka, disabling merging solely for this memory
> > optimization may not be a net win, because disabling slab merging tends
> > to increase overall memory usage.
Hi Joahnnes,
> Is this motivated by a production issue or a more a correctness thing?
It's more of a correctness thing :)
> It's somewhat tangential, but we've had practical problems with slab
> merging and ended up disabling it in the Meta fleet. It makes it
> difficult to identify culprits when there is a footprint regression in
> merged caches.
Oh, yeah. slab merging makes it harder to investigate which caches are
actually contributing to the regression.
> IIRC there was at least one instance where it merged
> wildly different lifetimes, which raises fragmentation concerns.
That is a valid concern indeed.
> In the end we turned it off and noted no meaningful usage difference.
That's very interesting observation, I was thinking slab merging should
have some benefit in saving memory...
> So I'm curious if there are cases where it tangibly helps. And I
> wonder whether default y makes sense given its observability and
> predictability implications.
/me digs some old email threads
Julian Pidancet tried to change the default behavior a few years ago.
v2: https://lore.kernel.org/linux-mm/20230629221910.359711-1-julian.pidancet@oracle.com
v1: https://lore.kernel.org/linux-mm/20230627132131.214475-1-julian.pidancet@oracle.com
Christoph Lameter at that time had a concern about its impact on systems
with larger pages.
https://lore.kernel.org/linux-mm/2df9debe-cbdc-abf7-4db1-1628b29df801@os.amperecomputing.com
David Rientjes measured the difference between enabling vs. disabling
slab merging in memory usage / performance on some benchmarks.
https://lore.kernel.org/linux-mm/3bcfa538-4474-09b7-1812-b4260b09256a@google.com
The observation was that SReclaimable was only slightly increased
(which probably isn't a big deal as it's reclaimable), but there were some
performance regressions when disabling slab merging, most notably a -18%
will-it-scale.context_switch1_per_thread_ops regression on skylake
(but not on cascade lake, presumably due to differences in μarch).
Looks like at that time it was concluded that disabling slab merging
by default probably wasn't a clear-cut decision, given that it showed
a measurable regression on benchmarks and without knowing which
real-world workloads would be affected by corner cases.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 14+ messages in thread