[PATCH 1/4] powerpc/pseries: Fix hcall tracing recursion in pv queued spinlocks
Naveen N. Rao
naveen.n.rao at linux.vnet.ibm.com
Tue Apr 27 23:43:33 AEST 2021
Nicholas Piggin wrote:
> The paravit queued spinlock slow path adds itself to the queue then
> calls pv_wait to wait for the lock to become free. This is implemented
> by calling H_CONFER to donate cycles.
>
> When hcall tracing is enabled, this H_CONFER call can lead to a spin
> lock being taken in the tracing code, which will result in the lock to
> be taken again, which will also go to the slow path because it queues
> behind itself and so won't ever make progress.
>
> An example trace of a deadlock:
>
> __pv_queued_spin_lock_slowpath
> trace_clock_global
> ring_buffer_lock_reserve
> trace_event_buffer_lock_reserve
> trace_event_buffer_reserve
> trace_event_raw_event_hcall_exit
> __trace_hcall_exit
> plpar_hcall_norets_trace
> __pv_queued_spin_lock_slowpath
> trace_clock_global
> ring_buffer_lock_reserve
> trace_event_buffer_lock_reserve
> trace_event_buffer_reserve
> trace_event_raw_event_rcu_dyntick
> rcu_irq_exit
> irq_exit
> __do_irq
> call_do_irq
> do_IRQ
> hardware_interrupt_common_virt
>
> Fix this by introducing plpar_hcall_norets_notrace(), and using that to
> make SPLPAR virtual processor dispatching hcalls by the paravirt
> spinlock code.
>
> Fixes: 20c0e8269e9d ("powerpc/pseries: Implement paravirt qspinlocks for SPLPAR")
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
> ---
> arch/powerpc/include/asm/hvcall.h | 3 +++
> arch/powerpc/include/asm/paravirt.h | 22 +++++++++++++++++++---
> arch/powerpc/platforms/pseries/hvCall.S | 10 ++++++++++
> arch/powerpc/platforms/pseries/lpar.c | 4 ++--
> 4 files changed, 34 insertions(+), 5 deletions(-)
Thanks for the fix! Some very minor nits below, but none the less:
Reviewed-by: Naveen N. Rao <naveen.n.rao at linux.vnet.ibm.com>
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index ed6086d57b22..0c92b01a3c3c 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -446,6 +446,9 @@
> */
> long plpar_hcall_norets(unsigned long opcode, ...);
>
> +/* Variant which does not do hcall tracing */
> +long plpar_hcall_norets_notrace(unsigned long opcode, ...);
> +
> /**
> * plpar_hcall: - Make a pseries hypervisor call
> * @opcode: The hypervisor call to make.
> diff --git a/arch/powerpc/include/asm/paravirt.h b/arch/powerpc/include/asm/paravirt.h
> index 5d1726bb28e7..3c13c2ec70a9 100644
> --- a/arch/powerpc/include/asm/paravirt.h
> +++ b/arch/powerpc/include/asm/paravirt.h
> @@ -30,17 +30,33 @@ static inline u32 yield_count_of(int cpu)
>
> static inline void yield_to_preempted(int cpu, u32 yield_count)
> {
It looks like yield_to_preempted() is only used by simple spin locks
today. I wonder if it makes more sense to put the below comment in
yield_to_any() which is used by the qspinlock code.
> - plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(cpu), yield_count);
> + /*
> + * Spinlock code yields and prods, so don't trace the hcalls because
> + * tracing code takes spinlocks which could recurse.
> + *
> + * These calls are made while the lock is not held, the lock slowpath
> + * yields if it can not acquire the lock, and unlock slow path might
> + * prod if a waiter has yielded). So this did not seem to be a problem
> + * for simple spin locks because technically it didn't recuse on the
^^^^^^
recurse
> + * lock. However the queued spin lock contended path is more strictly
> + * ordered: the H_CONFER hcall is made after the task has queued itself
> + * on the lock, so then recursing on the lock will queue up behind that
> + * (or worse: queued spinlocks uses tricks that assume a context never
> + * waits on more than one spinlock, so that may cause random
> + * corruption).
> + */
> + plpar_hcall_norets_notrace(H_CONFER,
> + get_hard_smp_processor_id(cpu), yield_count);
This can all be on a single line.
- Naveen
More information about the Linuxppc-dev
mailing list