Re: [PATCH RFC 3/4] mm/slab: fix a deadlock in memcg_alloc_abort_single()
From: Vlastimil Babka (SUSE)
Date: Fri Jun 26 2026 - 11:08:18 EST
On 6/24/26 15:11, Harry Yoo (Oracle) wrote:
> When kmalloc_nolock() successfully grabs a slab object but memcg aborts
> the allocation, the object is freed via __slab_free(). Calling
> __slab_free() in unknown context is not allowed and can lead to a
> deadlock.
>
> Free the object via defer_free() when spinning is not allowed.
>
> Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
> Closes: https://sashiko.dev/#/patchset/20260610-slab_alloc_flags-v2-0-7190909db118%40kernel.org?part=9
> Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock().")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Harry Yoo (Oracle) <harry@xxxxxxxxxx>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>
> ---
> mm/slub.c | 17 ++++++++++++-----
> 1 file changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 85760c8ff2e2..4a3618e3967e 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2459,7 +2459,8 @@ alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
>
> #ifdef CONFIG_MEMCG
>
> -static void memcg_alloc_abort_single(struct kmem_cache *s, void *object);
> +static void memcg_alloc_abort_single(struct kmem_cache *s, void *object,
> + bool allow_spin);
>
> static __fastpath_inline
> bool memcg_slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
> @@ -2477,7 +2478,9 @@ bool memcg_slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
> return true;
>
> if (likely(size == 1)) {
> - memcg_alloc_abort_single(s, *p);
> + bool allow_spin = alloc_flags_allow_spinning(ac->alloc_flags);
> +
> + memcg_alloc_abort_single(s, *p, allow_spin);
> *p = NULL;
> } else {
> kmem_cache_free_bulk(s, size, p);
> @@ -6436,16 +6439,20 @@ void slab_free(struct kmem_cache *s, struct slab *slab, void *object,
> #ifdef CONFIG_MEMCG
> /* Do not inline the rare memcg charging failed path into the allocation path */
> static noinline
> -void memcg_alloc_abort_single(struct kmem_cache *s, void *object)
> +void memcg_alloc_abort_single(struct kmem_cache *s, void *object, bool allow_spin)
> {
> struct slab *slab = virt_to_slab(object);
> bool init = slab_want_init_on_free(s);
> - bool allow_spin = true;
>
> alloc_tagging_slab_free_hook(s, slab, &object, 1);
>
> - if (likely(slab_free_hook(s, object, init, false, allow_spin)))
> + if (unlikely(!slab_free_hook(s, object, init, false, allow_spin)))
> + return;
> +
> + if (likely(allow_spin))
> __slab_free(s, slab, object, object, 1, _RET_IP_);
> + else
> + defer_free(s, object);
> }
> #endif
>
>