diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2023-01-21 19:53:52 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2023-01-30 20:07:18 +1100 |
commit | bc88ef663265676419555df2dc469a471c0add31 (patch) | |
tree | ab49b8da25d2e0dc73ce90bce1fe991665fee736 /arch | |
parent | fe6de81b610e5d0b9d2231acff2de74a35482e7d (diff) | |
download | lwn-bc88ef663265676419555df2dc469a471c0add31.tar.gz lwn-bc88ef663265676419555df2dc469a471c0add31.zip |
powerpc/64s: Fix local irq disable when PMIs are disabled
When PMI interrupts are soft-masked, local_irq_save() will clear the PMI
mask bit, allowing PMIs in and causing a race condition. This causes a
deadlock in native_hpte_insert via hash_preload, which depends on PMIs
being disabled since commit 8b91cee5eadd ("powerpc/64s/hash: Make hash
faults work in NMI context"). native_hpte_insert calls local_irq_save().
It's possible the lpar hash code is also affected when tracing is
enabled because __trace_hcall_entry() calls local_irq_save().
Fix this by making arch_local_irq_save() _or_ the IRQS_DISABLED bit into
the mask.
This was found with the stress_hpt option with a kbuild workload running
together with `perf record -g`.
Fixes: f442d004806e ("powerpc/64s: Add support to mask perf interrupts and replay them")
Fixes: 8b91cee5eadd ("powerpc/64s/hash: Make hash faults work in NMI context")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Just take the fix without the new warning]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20230121095352.2823517-1-npiggin@gmail.com
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/hw_irq.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 77fa88c2aed0..0b7d01d408ac 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -192,7 +192,7 @@ static inline void arch_local_irq_enable(void) static inline unsigned long arch_local_irq_save(void) { - return irq_soft_mask_set_return(IRQS_DISABLED); + return irq_soft_mask_or_return(IRQS_DISABLED); } static inline bool arch_irqs_disabled_flags(unsigned long flags) |