Re: [PATCH v2 13/16] mm/slab: allow __GFP_NOMEMALLOC and __GFP_NOWARN for kmalloc_nolock()
From: hu.shengming
Date: Fri Jun 12 2026 - 08:55:21 EST
Vlastimil Babka (SUSE) wrote:
> The two flags are added internally so there's no point for warning if
> they are passed by the caller as well, so allow them. This will allow
> simplifying obj_ext allocation under kmalloc_nolock().
>
> Also it's not necessary to have the extra alloc_gfp variable for adding
> the two flags. The original gfp_flags parameter is not used anywhere
> except for the warning. So remove alloc_gfp and directly modify and use
> gfp_flags everywhere.
>
> Signed-off-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>
> ---
> include/linux/slab.h | 3 ++-
> mm/slub.c | 19 ++++++++++---------
> 2 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/slab.h b/include/linux/slab.h
> index ce1c867dc0ba..b955f3cbb732 100644
> --- a/include/linux/slab.h
> +++ b/include/linux/slab.h
> @@ -1040,7 +1040,8 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> * kmalloc_nolock - Allocate an object of given size from any context.
> * @size: size to allocate
> * @gfp_flags: GFP flags. Only __GFP_ACCOUNT, __GFP_ZERO, __GFP_NO_OBJ_EXT
> - * allowed.
> + * allowed. Also __GFP_NOWARN and __GFP_NOMEMALLOC are allowed but added
> + * internally thus not necessary.
> * @node: node number of the target node.
> *
> * Return: pointer to the new object or NULL in case of error.
> diff --git a/mm/slub.c b/mm/slub.c
> index 6845e15c148a..847cad5203b2 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -5388,7 +5388,6 @@ EXPORT_SYMBOL(__kmalloc_noprof);
>
> void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node)
> {
> - gfp_t alloc_gfp = __GFP_NOWARN | __GFP_NOMEMALLOC | gfp_flags;
> size_t orig_size = size;
> unsigned int alloc_flags = SLAB_ALLOC_TRYLOCK;
> struct kmem_cache *s;
> @@ -5396,7 +5395,9 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> void *ret;
>
> VM_WARN_ON_ONCE(gfp_flags & ~(__GFP_ACCOUNT | __GFP_ZERO |
> - __GFP_NO_OBJ_EXT));
> + __GFP_NO_OBJ_EXT | __GFP_NOWARN | __GFP_NOMEMALLOC));
> +
> + gfp_flags |= __GFP_NOWARN | __GFP_NOMEMALLOC;
>
Hi Vlastimil,
While reviewing your patch, I spotted a potential GFP flag mismatch along the kmalloc_flags()
-> __kmalloc_nolock_noprof() call path. I cloned the slab/for-next branch to verify this and
successfully triggered a VM_WARN_ON_ONCE() in the __kmalloc_nolock_noprof() path.
Here is the observed trace:
[ 57.283791] ------------[ cut here ]------------
[ 57.284226] WARNING: mm/slub.c:5407 at __kmalloc_nolock_noprof+0x3ec/0x450, CPU#6: insmod/379
[ 57.285060] Modules linked in: slub_nolock(O+)
[ 57.285494] CPU: 6 UID: 0 PID: 379 Comm: insmod Tainted: G O 7.1.0-rc3-00036-g5ade53586fae-dirty #5 PREEMPT(lazy)
[ 57.286608] Tainted: [O]=OOT_MODULE
[ 57.286941] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
[ 57.288018] RIP: 0010:__kmalloc_nolock_noprof+0x3ec/0x450
[ 57.288543] Code: 01 00 8b 4c 24 04 41 89 c2 e9 dd fc ff ff b8 10 00 00 00 e9 f9 fd ff ff 90 0f 0b 90 f7 04 24 ff de b7 ff 0f 84 54
[ 57.290252] RSP: 0018:ffffa82840c73b68 EFLAGS: 00010206
[ 57.290752] RAX: 0000000000000000 RBX: 0000000000000003 RCX: ffffa82840c73bc8
[ 57.291428] RDX: 0000000000000000 RSI: 00000000002c2100 RDI: 0000000000000100
[ 57.292124] RBP: 0000000000000000 R08: ffffffffb853c968 R09: 0000000000009ffb
[ 57.292821] R10: 00000000000001d7 R11: ffffffffb850c980 R12: 00000000002c2100
[ 57.293485] R13: 0000000000000000 R14: ffffa82840c73bc8 R15: 0000000000000003
[ 57.294159] FS: 0000000006fa8880(0000) GS:ffff8f4ef9d5a000(0000) knlGS:0000000000000000
[ 57.294914] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 57.295464] CR2: 0000000006fac528 CR3: 000000003f9b6003 CR4: 0000000000770ef0
[ 57.296124] PKRU: 55555554
[ 57.296443] Call Trace:
[ 57.296702] <TASK>
[ 57.296914] ? vprintk_emit+0x22e/0x280
[ 57.297295] __kmalloc_flags_noprof+0x216/0x530
[ 57.297735] ? _printk+0x56/0x70
[ 57.298053] ? alloc_slab_obj_exts+0x89/0x1e0
[ 57.298474] alloc_slab_obj_exts+0x89/0x1e0
[ 57.298876] new_slab+0x2bc/0x660
[ 57.299200] ___slab_alloc+0x2ae/0x660
[ 57.299603] __kmalloc_nolock_noprof+0x151/0x450
[ 57.300050] _kmalloc_nolock_noprof+0x47/0x70
[ 57.300490] ? slub_nolock_init+0x127/0xff0 [slub_nolock]
[ 57.301013] slub_nolock_init+0x127/0xff0 [slub_nolock]
[ 57.301566] ? __pfx_slub_nolock_init+0x10/0x10 [slub_nolock]
[ 57.302197] do_one_initcall+0x44/0x220
[ 57.302598] ? do_init_module+0x1e/0x240
[ 57.302990] do_init_module+0x5f/0x240
[ 57.303357] __do_sys_init_module+0x162/0x190
[ 57.303783] do_syscall_64+0xf7/0x550
[ 57.304159] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 57.304648] RIP: 0033:0x4b8839
[ 57.304954] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 40
[ 57.306676] RSP: 002b:00007ffea38fdce8 EFLAGS: 00000246 ORIG_RAX: 00000000000000af
[ 57.307376] RAX: ffffffffffffffda RBX: 00007ffea38fe080 RCX: 00000000004b8839
[ 57.308044] RDX: 000000000062d4b5 RSI: 0000000000002790 RDI: 0000000006fa9d20
[ 57.308710] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000002790
[ 57.309366] R10: 0000000006fa9cc0 R11: 0000000000000246 R12: 00007ffea38fe088
[ 57.310040] R13: 000000000062d4b5 R14: 0000000000000000 R15: 0000000000000000
[ 57.310737] </TASK>
[ 57.310963] ---[ end trace 0000000000000000 ]---
With "# CONFIG_KMALLOC_PARTITION_CACHES is not set":
RSI: 00000000002c2100 -> gfp_flags
Decoding the GFP bits:
0x00000100 = __GFP_ZERO
0x00002000 = __GFP_NOWARN
0x00080000 = __GFP_NOMEMALLOC
0x00040000 = __GFP_COMP
0x00200000 = __GFP_THISNODE
The root cause:
Previously, the obj_ext allocation path(alloc_slab_obj_exts()) called kmalloc_nolock() with a
fixed set of flags(__GFP_ZERO | __GFP_NO_OBJ_EXT). After switching to kmalloc_flags(), the
full GFP mask from the upper allocation path propagates through the call chain.
In detail, ___slab_alloc() may append __GFP_THISNODE, and allocate_slab() adds __GFP_COMP
via s->allocflags. Both flags flow down unchanged into __kmalloc_nolock_noprof().
This patch only permits four flags (__GFP_ACCOUNT, __GFP_ZERO, __GFP_NOWARN and __GFP_NOMEMALLOC).
Since neither __GFP_THISNODE nor __GFP_COMP is in the allowed set, the warning is triggered.
Would the following fix be acceptable?
+#define KMALLOC_NOLOCK_ALLOWED_GFP \
+ (__GFP_ACCOUNT | __GFP_ZERO | __GFP_NOWARN | __GFP_NOMEMALLOC)
+
/*
* The only version of kmalloc_node() that takes alloc_flags and thus can
* determine on its own whether to handle the allocation via kmalloc_nolock() or
@@ -5548,6 +5564,7 @@ void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,
return __do_kmalloc_node(size, NULL, flags, node,
PASS_TOKEN_PARAM(token), &ac);
} else {
+ flags &= KMALLOC_NOLOCK_ALLOWED_GFP;
return __kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(size, token),
flags, node, &ac);
}
--
With Best Regards,
Shengming
> if (unlikely(!size))
> return ZERO_SIZE_PTR;
> @@ -5415,7 +5416,7 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> retry:
> if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
> return NULL;
> - s = kmalloc_slab(size, NULL, alloc_gfp, PASS_TOKEN_PARAM(token));
> + s = kmalloc_slab(size, NULL, gfp_flags, PASS_TOKEN_PARAM(token));
>
> if (!(s->flags & __CMPXCHG_DOUBLE) && !kmem_cache_debug(s))
> /*
> @@ -5429,7 +5430,7 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> */
> return NULL;
>
> - ret = alloc_from_pcs(s, alloc_gfp, alloc_flags, node);
> + ret = alloc_from_pcs(s, gfp_flags, alloc_flags, node);
> if (ret)
> goto success;
>
> @@ -5445,7 +5446,7 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> * kfence_alloc. Hence call __slab_alloc_node() (at most twice)
> * and slab_post_alloc_hook() directly.
> */
> - ret = __slab_alloc_node(s, alloc_gfp, node, &ac);
> + ret = __slab_alloc_node(s, gfp_flags, node, &ac);
>
> /*
> * It's possible we failed due to trylock as we preempted someone with
> @@ -5458,8 +5459,8 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
> size = s->object_size + 1;
> /*
> * Another alternative is to
> - * if (memcg) alloc_gfp &= ~__GFP_ACCOUNT;
> - * else if (!memcg) alloc_gfp |= __GFP_ACCOUNT;
> + * if (memcg) gfp_flags &= ~__GFP_ACCOUNT;
> + * else if (!memcg) gfp_flags |= __GFP_ACCOUNT;
> * to retry from bucket of the same size.
> */
> can_retry = false;
> @@ -5468,9 +5469,9 @@ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, in
>
> success:
> maybe_wipe_obj_freeptr(s, ret);
> - slab_post_alloc_hook(s, alloc_gfp, 1, &ret, &ac);
> + slab_post_alloc_hook(s, gfp_flags, 1, &ret, &ac);
>
> - ret = kasan_kmalloc(s, ret, orig_size, alloc_gfp);
> + ret = kasan_kmalloc(s, ret, orig_size, gfp_flags);
> return ret;
> }
> EXPORT_SYMBOL_GPL(_kmalloc_nolock_noprof);
>
> --
> 2.54.0
>