ftrace: Add ftrace_test_recursion_trylock() helper function

To make it easier for ftrace callbacks to have recursion protection, provide
a ftrace_test_recursion_trylock() and ftrace_test_recursion_unlock() helper
that tests for recursion.

Link: https://lkml.kernel.org/r/20201028115612.634927593@goodmis.org
Link: https://lkml.kernel.org/r/20201106023546.378584067@goodmis.org

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Steven Rostedt (VMware) 2020-11-05 21:32:37 -05:00
parent 0264c8c9e1
commit 6e4eb9cb22
2 changed files with 30 additions and 7 deletions

View File

@ -183,5 +183,30 @@ static __always_inline void trace_clear_recursion(int bit)
current->trace_recursion = val; current->trace_recursion = val;
} }
/**
* ftrace_test_recursion_trylock - tests for recursion in same context
*
* Use this for ftrace callbacks. This will detect if the function
* tracing recursed in the same context (normal vs interrupt),
*
* Returns: -1 if a recursion happened.
* >= 0 if no recursion
*/
static __always_inline int ftrace_test_recursion_trylock(void)
{
return trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
}
/**
* ftrace_test_recursion_unlock - called when function callback is complete
* @bit: The return of a successful ftrace_test_recursion_trylock()
*
* This is used at the end of a ftrace callback.
*/
static __always_inline void ftrace_test_recursion_unlock(int bit)
{
trace_clear_recursion(bit);
}
#endif /* CONFIG_TRACING */ #endif /* CONFIG_TRACING */
#endif /* _LINUX_TRACE_RECURSION_H */ #endif /* _LINUX_TRACE_RECURSION_H */

View File

@ -141,22 +141,20 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
if (unlikely(!tr->function_enabled)) if (unlikely(!tr->function_enabled))
return; return;
bit = ftrace_test_recursion_trylock();
if (bit < 0)
return;
pc = preempt_count(); pc = preempt_count();
preempt_disable_notrace(); preempt_disable_notrace();
bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
if (bit < 0)
goto out;
cpu = smp_processor_id(); cpu = smp_processor_id();
data = per_cpu_ptr(tr->array_buffer.data, cpu); data = per_cpu_ptr(tr->array_buffer.data, cpu);
if (!atomic_read(&data->disabled)) { if (!atomic_read(&data->disabled)) {
local_save_flags(flags); local_save_flags(flags);
trace_function(tr, ip, parent_ip, flags, pc); trace_function(tr, ip, parent_ip, flags, pc);
} }
trace_clear_recursion(bit); ftrace_test_recursion_unlock(bit);
out:
preempt_enable_notrace(); preempt_enable_notrace();
} }