powerpc: Fix hcall tracepoint recursion
Spinlocks on shared processor partitions use H_YIELD to notify the hypervisor we are waiting on another virtual CPU. Unfortunately this means the hcall tracepoints can recurse. The patch below adds a percpu depth and checks it on both the entry and exit hcall tracepoints. Signed-off-by: Anton Blanchard <anton@samba.org> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> CC: stable@kernel.org
This commit is contained in:
committed by
Benjamin Herrenschmidt
parent
429f4d8d20
commit
57cdfdf829
@@ -713,6 +713,13 @@ EXPORT_SYMBOL(arch_free_page);
|
|||||||
/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
|
/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
|
||||||
extern long hcall_tracepoint_refcount;
|
extern long hcall_tracepoint_refcount;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the tracing code might execute hcalls we need to guard against
|
||||||
|
* recursion. One example of this are spinlocks calling H_YIELD on
|
||||||
|
* shared processor partitions.
|
||||||
|
*/
|
||||||
|
static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
|
||||||
|
|
||||||
void hcall_tracepoint_regfunc(void)
|
void hcall_tracepoint_regfunc(void)
|
||||||
{
|
{
|
||||||
hcall_tracepoint_refcount++;
|
hcall_tracepoint_refcount++;
|
||||||
@@ -725,12 +732,42 @@ void hcall_tracepoint_unregfunc(void)
|
|||||||
|
|
||||||
void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
|
void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int *depth;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
depth = &__get_cpu_var(hcall_trace_depth);
|
||||||
|
|
||||||
|
if (*depth)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
(*depth)++;
|
||||||
trace_hcall_entry(opcode, args);
|
trace_hcall_entry(opcode, args);
|
||||||
|
(*depth)--;
|
||||||
|
|
||||||
|
out:
|
||||||
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __trace_hcall_exit(long opcode, unsigned long retval,
|
void __trace_hcall_exit(long opcode, unsigned long retval,
|
||||||
unsigned long *retbuf)
|
unsigned long *retbuf)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int *depth;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
depth = &__get_cpu_var(hcall_trace_depth);
|
||||||
|
|
||||||
|
if (*depth)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
(*depth)++;
|
||||||
trace_hcall_exit(opcode, retval, retbuf);
|
trace_hcall_exit(opcode, retval, retbuf);
|
||||||
|
(*depth)--;
|
||||||
|
|
||||||
|
out:
|
||||||
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user