Re: [PATCH] mm/slub: serve slabobj_ext array from a strictly larger kmalloc cache

From: Harry Yoo

Date: Thu Jul 02 2026 - 01:15:14 EST




On 7/1/26 8:37 PM, Suren Baghdasaryan wrote:
> On Wed, Jul 1, 2026 at 12:42 AM Harry Yoo <harry@xxxxxxxxxx> wrote:
>> On 7/1/26 1:53 PM, Harry Yoo wrote:
>>> On 7/1/26 1:30 PM, Harry Yoo wrote:
>>>> We can do that in pre-7.2 kernels, by teaching kmalloc_type() and
>>>> kmalloc_slab() select the new KMALLOC_TYPE based on __GFP_NO_OBJ_EXT?
>>>>
>>>> e.g.) Select the new KMALLOC_TYPE when KMALLOC_NOT_NORMAL_BITS is not
>>>> set AND __GFP_NO_OBJ_EXT is set.
>>>
>>> Uh, this is bit subtle though.
>>>
>>> In some cases KMALLOC_DMA == KMALLOC_NORMAL,
>>> KMALLOC_CGROUP == KMALLOC_NORMAL,
>>> or KMALLOC_RECLAIM == KMALLOC_NORMAL.
>>>
>>> Just checking KMALLOC_NOT_NORMAL_BITS is misleading.
>>
>> Here's a prototype for slab/for-next. Backporting it requires handling
>> __GFP_NO_OBJ_EXT instead of SLAB_ALLOC_NO_RECURSE, but shouldn't be
>> too difficult. Now writing changelog and going through testing...
>>
>> diff --git a/include/linux/slab.h b/include/linux/slab.h
>> index 51f03f18c9a7..91a71537a2fe 100644
>> --- a/include/linux/slab.h
>> +++ b/include/linux/slab.h
>> @@ -684,6 +684,26 @@ static inline unsigned int arch_slab_minalign(void)
>> #define KMALLOC_PARTITION_CACHES_NR 0
>> #endif
>>
>> +/*
>> + * SLUB needs a separate kmalloc type, KMALLOC_NO_RECURSE, when
>> internal slab
>> + * metadata of kmalloc objects can be allocated from the same kmalloc type.
>> + */
>> +#if defined(CONFIG_MEM_ALLOC_PROFILING)
>> +/*
>> + * Memory allocation profiling can allocate internal slab metadata
>> + * for any slab cache.
>> + */
>> +#define HAS_KMALLOC_NO_RECURSE
>> +#elif defined(CONFIG_SLUB_TINY) && defined(CONFIG_MEMCG)
>> +/*
>> + * Accounted slab objects are usually allocated from KMALLOC_CGROUP.
>> + * On SLUB_TINY, those can be allocated from KMALLOC_NORMAL because
>> + * KMALLOC_RECLAIM aliases with KMALLOC_CGROUP and has higher priority than
>> + * KMALLOC_CGROUP.
>> + */
>> +#define HAS_KMALLOC_NO_RECURSE
>> +#endif
>> +
>> /*
>> * Whenever changing this, take care of that kmalloc_type() and
>> * create_kmalloc_caches() still work as intended.
>> @@ -702,6 +722,9 @@ enum kmalloc_cache_type {
>> #endif
>> KMALLOC_PARTITION_START = KMALLOC_NORMAL,
>> KMALLOC_PARTITION_END = KMALLOC_PARTITION_START +
>> KMALLOC_PARTITION_CACHES_NR,
>> +#ifdef HAS_KMALLOC_NO_RECURSE
>> + KMALLOC_NO_RECURSE,
>> +#endif
>> #ifdef CONFIG_SLUB_TINY
>> KMALLOC_RECLAIM = KMALLOC_NORMAL,
>> #else
>> @@ -716,6 +739,16 @@ enum kmalloc_cache_type {
>> NR_KMALLOC_TYPES
>> };
>>
>> +#if !defined(HAS_KMALLOC_NO_RECURSE) && defined(CONFIG_SLAB_OBJ_EXT)
>> +/*
>> + * kmalloc_flags() with SLAB_ALLOC_NO_RECURSE should not use KMALLOC_NORMAL
>> + * if any of these alias with KMALLOC_NORMAL.
>> + */
>> +static_assert(KMALLOC_DMA != KMALLOC_NORMAL);
>> +static_assert(KMALLOC_CGROUP != KMALLOC_NORMAL);
>> +static_assert(KMALLOC_RECLAIM != KMALLOC_NORMAL);
>> +#endif
>> +
>> typedef struct kmem_cache * kmem_buckets[KMALLOC_SHIFT_HIGH + 1];
>>
>> extern kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES];
>> diff --git a/mm/slab.h b/mm/slab.h
>> index 281a65233795..ba0560111488 100644
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -386,12 +386,21 @@ static inline unsigned int
>> size_index_elem(unsigned int bytes)
>> * KMALLOC_MAX_CACHE_SIZE and the caller must check that.
>> */
>> static inline struct kmem_cache *
>> -kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t
>> token)
>> +kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t
>> token,
>> + unsigned int alloc_flags)
>> {
>> unsigned int index;
>> + enum kmalloc_cache_type type = kmalloc_type(flags, token);
>> +
>> +#ifdef HAS_KMALLOC_NO_RECURSE
>> + if (type >= KMALLOC_PARTITION_START &&
>> + type <= KMALLOC_PARTITION_END &&
>> + (alloc_flags & SLAB_ALLOC_NO_RECURSE))
>> + type = KMALLOC_NO_RECURSE;
>> +#endif
>
> Overall your approach LGTM, just here why not simply:

Thanks! There's been few chances since this prototype...

1. KMALLOC_NO_RECURSE -> KMALLOC_NO_OBJ_EXT
2. Unlike KMALLOC_NO_RECURSE, KMALLOC_NO_OBJ_EXT caches have sheaves
3. To allow 2. SLAB_NO_SHEAVES was decoupled from SLAB_NO_OBJ_EXT.
Now SLAB_NO_OBJ_EXT disallows obj_exts only.
4. with CONFIG_SLAB_OBJ_EXT=y, KMALLOC_NO_OBJ_EXT caches are created
by default but remains unused until needed.

> +#ifdef HAS_KMALLOC_NO_RECURSE
> + if (alloc_flags & SLAB_ALLOC_NO_RECURSE)
> + type = KMALLOC_NO_RECURSE;
> +#endif

Did that in the RFC [1], thanks.

[1]
https://lore.kernel.org/lkml/20260702-kmalloc-no-objext-v1-0-167175008538@xxxxxxxxxx

--
Cheers,
Harry / Hyeonggon

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature