On Mon, Jun 01, 2026 at 06:57:46PM +0530, Venkat Rao Bagalkote wrote:
> Greetings!!!
> 
> 
> I am observing multiple reproducible WARN_ONs related to RCU and lockdep IRQ
> state tracking on a Power11 pSeries system when running on latest linux-next
> kernel.
> 
> 
> Environment:
>   Architecture: ppc64le (Power11, pSeries LPAR)
>   Kernel: 7.1.0-rc5-next-20260529
>   Config: PREEMPT(lazy)
>           CONFIG_LOCKDEP=y
>           CONFIG_PROVE_LOCKING=y
> 
> 
> 
[...]
> Warning2:
> 
> [    0.010098] ------------[ cut here ]------------
> [    0.010103] DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context())
> [    0.010107] WARNING: kernel/locking/lockdep.c:4406 at
> lockdep_hardirqs_on_prepare+0x22c/0x2d4, CPU#0: swapper/0/1
> [    0.010116] Modules linked in:
> [    0.010120] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Tainted: G     W       
>    7.1.0-rc5-next-20260529 #1 PREEMPT(lazy)
> [    0.010125] Tainted: [W]=WARN
> [    0.010127] Hardware name: IBM,9080-HEX Power11 (architected) 0x820200
> 0xf000007 of:IBM,FW1110.01 (NH1110_069) hv:phyp pSeries
> [    0.010131] NIP:  c00000000031549c LR: c000000000315498 CTR:
> 0000000000000000
> [    0.010135] REGS: c0000000045bf100 TRAP: 0700   Tainted: G   W           
> (7.1.0-rc5-next-20260529)
> [    0.010139] MSR:  8000000002021033 <SF,VEC,ME,IR,DR,RI,LE>  CR: 44044228 
> XER: 00000005
> [    0.010147] CFAR: c00000000022e9d4 IRQMASK: 3
> [    0.010147] GPR00: c000000000315498 c0000000045bf3c0 c000000001ccf100
> 000000000000002e
> [    0.010147] GPR04: 3fffffffffff7fff c0000000045bf1b0 c0000000045bf1a8
> 0000000000000000
> [    0.010147] GPR08: c0000000029d1230 0000000000010002 c0000000048b2b00
> 0000000000000003
> [    0.010147] GPR12: c000000002d514e0 c000000003ea1000 c000000000011ae4
> 0000000000000000
> [    0.010147] GPR16: 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000
> [    0.010147] GPR20: 0000000000000000 0000000000000004 c000000000272684
> c0000000029bb0c0
> [    0.010147] GPR24: 0000000ebc171000 c000000ebeb63850 c000000003084d00
> c00000000308b2d0
> [    0.010147] GPR28: c00000000002a488 0000000000000001 0000000000000000
> c000000002246e08
> [    0.010188] NIP [c00000000031549c]
> lockdep_hardirqs_on_prepare+0x22c/0x2d4
> [    0.010192] LR [c000000000315498] lockdep_hardirqs_on_prepare+0x228/0x2d4
> [    0.010196] Call Trace:
> [    0.010198] [c0000000045bf3c0] [c000000000315498]
> lockdep_hardirqs_on_prepare+0x228/0x2d4 (unreliable)
> [    0.010204] [c0000000045bf430] [c0000000004bb778]
> trace_hardirqs_on+0xec/0x1b0
> [    0.010209] [c0000000045bf4b0] [c0000000015ad574]
> irqentry_exit+0x58c/0xe1c
> [    0.010213] [c0000000045bf540] [c00000000002a488]
> timer_interrupt+0x210/0x564
> [    0.010219] [c0000000045bf5f0] [c00000000003b960]
> __replay_soft_interrupts+0x14c/0x374
> [    0.010224] [c0000000045bf7d0] [c00000000003bd74]
> arch_local_irq_restore.part.0+0x1ec/0x224
> [    0.010230] [c0000000045bf810] [c0000000015c17d4]
> _raw_spin_unlock_irqrestore+0x54/0xac
> [    0.010235] [c0000000045bf840] [c0000000002cdd54]
> set_user_nice+0x110/0x220
> [    0.010240] [c0000000045bf8e0] [c000000000266a94]
> create_worker+0x13c/0x310
> [    0.010245] [c0000000045bf9a0] [c0000000002726f4]
> workqueue_prepare_cpu+0x70/0xe4
> [    0.010251] [c0000000045bf9e0] [c000000000232604]
> cpuhp_invoke_callback+0x1e8/0x3c0
> [    0.010256] [c0000000045bfa50] [c000000000232924]
> __cpuhp_invoke_callback_range+0x148/0x230
> [    0.010261] [c0000000045bfaf0] [c000000000234f68] _cpu_up+0x19c/0x3cc
> [    0.010265] [c0000000045bfbb0] [c00000000023533c] cpu_up+0x1a4/0x1f4
> [    0.010269] [c0000000045bfc40] [c00000000203d1f4]
> bringup_nonboot_cpus+0xbc/0x128
> [    0.010275] [c0000000045bfca0] [c00000000204b98c] smp_init+0x44/0xd0
> [    0.010279] [c0000000045bfd00] [c000000002006d4c]
> kernel_init_freeable+0x23c/0x3b0
> [    0.010284] [c0000000045bfdc0] [c000000000011b0c] kernel_init+0x30/0x274
> [    0.010288] [c0000000045bfe30] [c00000000000debc]
> ret_from_kernel_user_thread+0x14/0x1c
> [    0.010292] ---- interrupt: 0 at 0x0
> [    0.010296] Code: 4182ff74 3d22013c 3929c1d4 81290000 2c090000 4082ff60
> 3c82ffda 3c62ffd9 3884f998 38634590 4bf19461 60000000 <0fe00000> 4bffff40
> 60000000 60000000
> [    0.010310] irq event stamp: 7440
> [    0.010312] hardirqs last  enabled at (7439): [<c0000000015c1824>]
> _raw_spin_unlock_irqrestore+0xa4/0xac
> [    0.010317] hardirqs last disabled at (7440): [<c00000000003bc30>]
> arch_local_irq_restore.part.0+0xa8/0x224
> [    0.010323] softirqs last  enabled at (0): [<c00000000022b6ac>]
> copy_process+0xb24/0x1dec
> [    0.010328] softirqs last disabled at (0): [<0000000000000000>] 0x0
> [    0.010331] ---[ end trace 0000000000000000 ]---
> 
Root cause:
On powerpc, a soft-masked interrupt that arrives while IRQs are soft-disabled
is recorded in irq_happened. It is replayed when IRQs are re-enabled. Here
that happens through 
_raw_spin_unlock_irqrestore()
        arch_local_irq_restore()
                __replay_soft_interrupts()
                        timer_interrupt().
Before replaying, arch_local_irq_restore() deliberately calls irq_enter() at
line 317. The reason is to keep softirqs from running inside the replayed
handlers. irq_enter() does preempt_count_add(HARDIRQ_OFFSET) and
lockdep_hardirq_enter(). So the replayed handler starts with one hardirq level
already held.
The replayed timer_interrupt() is defined with DEFINE_INTERRUPT_HANDLER_ASYNC.
It runs irq_enter_rcu(), then the handler body, then irq_exit_rcu(), then
irqentry_exit(). In a real hardirq the nesting depth goes 0 → 1 → 0 over this
sequence. In the replay case it goes 1 → 2 → 1. This matches your "preempt
count is 2 compared to 1" observation.
When irqentry_exit() takes the return-to-kernel path with IRQs enabled in the
interrupted context, it calls trace_hardirqs_on(). That reaches
lockdep_hardirqs_on_prepare(). Lockdep expects hardirq context to be fully
unwound at that point. It checks DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context())
at line 4448. The per-CPU hardirq_context is still 1, left over from the
outer irq_enter() in arch_local_irq_restore(). So the warning fires, and
lockdep disables itself (debug_locks is cleared).

The replay path's own irq_enter()/irq_exit() bracket is still open when the
generic entry code's irqentry_exit() tries to re-establish the "IRQs on" state.
This is not a real nested-IRQ bug. The generic entry code simply assumes it runs
outside any hardirq context.

This warning is harmless and we are working on this to fix it.

Regards,
Mukesh

[...]

Reply via email to