Re: [linus:master] [mm/vmalloc] a061578043: BUG:spinlock_trylock_failure_on_UP_on_CPU

Matthew Wilcox
2025-12-19T20:26:19Z

On Wed, Dec 10, 2025 at 02:10:28PM +0800, kernel test robot wrote:
> kernel test robot noticed "BUG:spinlock_trylock_failure_on_UP_on_CPU" on:
>
> commit: a0615780439938e8e61343f1f92a4c54a71dc6a5 ("mm/vmalloc: request large order pages from buddy allocator")

I agree with Andrew; this commit is only exposing, not causing the bug.

> [ 1046.632156][ C0] BUG: spinlock trylock failure on UP on CPU#0, kcompactd0/28

The first thing to note is that this will only show up on CONFIG_SMP=n
builds, on account of it being behind a #ifndef. So almost nobody will
ever see it. It's also a failure of a trylock, so the worst consequence
is going to be performance.

> [ 1046.640168][ C0] spin_dump (kernel/locking/spinlock_debug.c:71)
> [ 1046.640853][ C0] do_raw_spin_trylock (kernel/locking/spinlock_debug.c:?)

This comes from SPIN_BUG_ON(!ret, lock, "trylock failure on UP");

> [ 1046.641678][ C0] _raw_spin_trylock (include/linux/spinlock_api_smp.h:89 kernel/locking/spinlock.c:138)
> [ 1046.642473][ C0] __free_frozen_pages (mm/page_alloc.c:2973)

pcp = pcp_spin_trylock(zone->per_cpu_pageset, UP_flags);

> [ 1046.651984][ C0] <TASK>
> [ 1046.652466][ C0] asm_sysvec_apic_timer_interrupt (arch/x86/include/asm/idtentry.h:697)
> [ 1046.653389][ C0] RIP: 0010:_raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:95 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194)
> [ 1046.654391][ C0] Code: 00 44 89 f6 c1 ee 09 48 c7 c7 e0 f2 7e 86 31 d2 31 c9 e8 e8 dd 80 fd 4d 85 f6 74 05 e8 de e5 fd ff 0f ba e3 09 73 01 fb 31 f6 <ff> 0d 2f dc 6f 01 0f 95 c3 40 0f 94 c6 48 c7 c7 10 f3 7e 86 31 d2
> All code
> ========
> 0: 00 44 89 f6 add %al,-0xa(%rcx,%rcx,4)
> 4: c1 ee 09 shr $0x9,%esi
> 7: 48 c7 c7 e0 f2 7e 86 mov $0xffffffff867ef2e0,%rdi
> e: 31 d2 xor %edx,%edx
> 10: 31 c9 xor %ecx,%ecx
> 12: e8 e8 dd 80 fd call 0xfffffffffd80ddff
> 17: 4d 85 f6 test %r14,%r14
> 1a: 74 05 je 0x21
> 1c: e8 de e5 fd ff call 0xfffffffffffde5ff
> 21: 0f ba e3 09 bt $0x9,%ebx
> 25: 73 01 jae 0x28
> 27: fb sti
> 28: 31 f6 xor %esi,%esi
> 2a:* ff 0d 2f dc 6f 01 decl 0x16fdc2f(%rip) # 0x16fdc5f <-- trapping instruction
> 30: 0f 95 c3 setne %bl
> 33: 40 0f 94 c6 sete %sil
> 37: 48 c7 c7 10 f3 7e 86 mov $0xffffffff867ef310,%rdi
> 3e: 31 d2 xor %edx,%edx
>
> Code starting with the faulting instruction
> ===========================================
> 0: ff 0d 2f dc 6f 01 decl 0x16fdc2f(%rip) # 0x16fdc35
> 6: 0f 95 c3 setne %bl
> 9: 40 0f 94 c6 sete %sil
> d: 48 c7 c7 10 f3 7e 86 mov $0xffffffff867ef310,%rdi
> 14: 31 d2 xor %edx,%edx
> [ 1046.657511][ C0] RSP: 0000:ffffc900001cfb50 EFLAGS: 00000246
> [ 1046.658482][ C0] RAX: 0000000000000000 RBX: 0000000000000206 RCX: 0000000000000000
> [ 1046.659740][ C0] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
> [ 1046.660979][ C0] RBP: ffffc900001cfb68 R08: 0000000000000000 R09: 0000000000000000
> [ 1046.662239][ C0] R10: 0000000000000000 R11: 0000000000000000 R12: ffff888807e35f50
> [ 1046.663505][ C0] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
> [ 1046.664741][ C0] free_pcppages_bulk (mm/page_alloc.c:1494)

Line 1494 is a } so I presume this is really 1493:
spin_unlock_irqrestore(&zone->lock, flags);
... which makes sense; if an interrupt comes in during the IRQ-disabled
section, it's going to be serviced when we re-enable interrupts.

> [ 1046.665618][ C0] drain_pages_zone (include/linux/spinlock.h:391 mm/page_alloc.c:2632)

And this is where we do:

struct per_cpu_pages *pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu);
spin_lock(&pcp->lock);
free_pcppages_bulk(zone, to_drain, pcp, 0);

Now, as I recall, we are very much doing this on purpose. We decided
not to disable interrupts at this point for improved interrupt
latency, accepting the possibility that we'd occasionally fail
the trylock. Except on UP that's now an assertion failure.

How to fix?