Re: [PATCH mm-hotfixes 1/2] mm/page_alloc: return NULL early from alloc_frozen_pages_nolock() in NMI on UP
From: Harry Yoo (Oracle)
Date: Mon Apr 27 2026 - 01:53:52 EST
Apologies, I meant to run git sendmail --dry-run but messed it up
and sent V1 twice :/ (w/o cover letter). To avoid confusion, I will
send V2 with the cover letter. (Also I realize that I didn't add Cc:
stable on each patch, so will address that as well.)
On Mon, Apr 27, 2026 at 02:47:34PM +0900, Harry Yoo (Oracle) wrote:
> On UP kernels (!CONFIG_SMP), spin_trylock() is a no-op that
> unconditionally succeeds even when the lock is already held. As a
> result, alloc_frozen_pages_nolock() called from NMI context can
> re-enter rmqueue() and acquire the zone lock that the interrupted
> context is already holding, corrupting the freelists.
>
> With CONFIG_DEBUG_SPINLOCK on UP, the following BUG is triggered with
> the slub_kunit test module:
>
> BUG: spinlock trylock failure on UP on CPU#0, kunit_try_catch/243
> [...]
> Call Trace:
> <NMI>
> dump_stack_lvl+0x3f/0x60
> do_raw_spin_trylock+0x41/0x50
> _raw_spin_trylock+0x24/0x50
> rmqueue.isra.0+0x2a9/0xa70
> get_page_from_freelist+0xeb/0x450
> alloc_frozen_pages_nolock_noprof+0x111/0x1e0
> allocate_slab+0x42a/0x500
> ___slab_alloc+0xa7/0x4c0
> kmalloc_nolock_noprof+0x164/0x310
> [...]
> </NMI>
>
> Fix this by returning NULL early when invoked from NMI on a UP kernel.
>
> Link: https://lore.kernel.org/linux-mm/ad_cqe51pvr1WaDg@hyeyoo
> Fixes: d7242af86434 ("mm: Introduce alloc_frozen_pages_nolock()")
> Signed-off-by: Harry Yoo (Oracle) <harry@xxxxxxxxxx>
> ---
> mm/page_alloc.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 71859993dd54..23c7298d3be2 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -7737,6 +7737,11 @@ struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned
> */
> if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
> return NULL;
> +
> + /* On UP, spin_trylock() always succeeds even when it is locked */
> + if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
> + return NULL;
> +
> if (!pcp_allowed_order(order))
> return NULL;
>
> --
> 2.43.0
>
--
Cheers,
Harry / Hyeonggon