Skip to content

Commit 2c8c89b

Browse files
npigginmpe
authored andcommitted
powerpc/pseries: Fix hcall tracing recursion in pv queued spinlocks
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. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Reviewed-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210508101455.1578318-2-npiggin@gmail.com
1 parent 5d510ed commit 2c8c89b

4 files changed

Lines changed: 33 additions & 5 deletions

File tree

arch/powerpc/include/asm/hvcall.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@
448448
*/
449449
long plpar_hcall_norets(unsigned long opcode, ...);
450450

451+
/* Variant which does not do hcall tracing */
452+
long plpar_hcall_norets_notrace(unsigned long opcode, ...);
453+
451454
/**
452455
* plpar_hcall: - Make a pseries hypervisor call
453456
* @opcode: The hypervisor call to make.

arch/powerpc/include/asm/paravirt.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,35 @@ static inline u32 yield_count_of(int cpu)
2828
return be32_to_cpu(yield_count);
2929
}
3030

31+
/*
32+
* Spinlock code confers and prods, so don't trace the hcalls because the
33+
* tracing code takes spinlocks which can cause recursion deadlocks.
34+
*
35+
* These calls are made while the lock is not held: the lock slowpath yields if
36+
* it can not acquire the lock, and unlock slow path might prod if a waiter has
37+
* yielded). So this may not be a problem for simple spin locks because the
38+
* tracing does not technically recurse on the lock, but we avoid it anyway.
39+
*
40+
* However the queued spin lock contended path is more strictly ordered: the
41+
* H_CONFER hcall is made after the task has queued itself on the lock, so then
42+
* recursing on that lock will cause the task to then queue up again behind the
43+
* first instance (or worse: queued spinlocks use tricks that assume a context
44+
* never waits on more than one spinlock, so such recursion may cause random
45+
* corruption in the lock code).
46+
*/
3147
static inline void yield_to_preempted(int cpu, u32 yield_count)
3248
{
33-
plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(cpu), yield_count);
49+
plpar_hcall_norets_notrace(H_CONFER, get_hard_smp_processor_id(cpu), yield_count);
3450
}
3551

3652
static inline void prod_cpu(int cpu)
3753
{
38-
plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
54+
plpar_hcall_norets_notrace(H_PROD, get_hard_smp_processor_id(cpu));
3955
}
4056

4157
static inline void yield_to_any(void)
4258
{
43-
plpar_hcall_norets(H_CONFER, -1, 0);
59+
plpar_hcall_norets_notrace(H_CONFER, -1, 0);
4460
}
4561
#else
4662
static inline bool is_shared_processor(void)

arch/powerpc/platforms/pseries/hvCall.S

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ END_FTR_SECTION(0, 1); \
102102
#define HCALL_BRANCH(LABEL)
103103
#endif
104104

105+
_GLOBAL_TOC(plpar_hcall_norets_notrace)
106+
HMT_MEDIUM
107+
108+
mfcr r0
109+
stw r0,8(r1)
110+
HVSC /* invoke the hypervisor */
111+
lwz r0,8(r1)
112+
mtcrf 0xff,r0
113+
blr /* return r3 = status */
114+
105115
_GLOBAL_TOC(plpar_hcall_norets)
106116
HMT_MEDIUM
107117

arch/powerpc/platforms/pseries/lpar.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,8 +1830,7 @@ void hcall_tracepoint_unregfunc(void)
18301830

18311831
/*
18321832
* Since the tracing code might execute hcalls we need to guard against
1833-
* recursion. One example of this are spinlocks calling H_YIELD on
1834-
* shared processor partitions.
1833+
* recursion.
18351834
*/
18361835
static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
18371836

0 commit comments

Comments
 (0)