ftrace: Have ftrace_ops_get_func() handle RCU and PER_CPU flags too
Jiri Olsa noted that the change to replace the control_ops did not update the trampoline for when running perf on a single CPU and with CONFIG_PREEMPT disabled (where dynamic ops, like perf, can use trampolines directly). The result was that perf function could be called when RCU is not watching as well as not handle the ftrace_local_disable(). Modify the ftrace_ops_get_func() to also check the RCU and PER_CPU ops flags and use the recursive function if they are set. The recursive function is modified to check those flags and execute the appropriate checks if they are set. Link: http://lkml.kernel.org/r/20151201134213.GA14155@krava.brq.redhat.com Reported-by: Jiri Olsa <jolsa@redhat.com> Patch-fixed-up-by: Jiri Olsa <jolsa@redhat.com> Tested-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
parent
ba27f2bc73
commit
c68c0fa293
1 changed files with 18 additions and 12 deletions
|
@ -115,9 +115,6 @@ static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
|
|||
ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
|
||||
static struct ftrace_ops global_ops;
|
||||
|
||||
static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *op, struct pt_regs *regs);
|
||||
|
||||
#if ARCH_SUPPORTS_FTRACE_OPS
|
||||
static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *op, struct pt_regs *regs);
|
||||
|
@ -5231,20 +5228,29 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
|
|||
|
||||
/*
|
||||
* If there's only one function registered but it does not support
|
||||
* recursion, this function will be called by the mcount trampoline.
|
||||
* This function will handle recursion protection.
|
||||
* recursion, needs RCU protection and/or requires per cpu handling, then
|
||||
* this function will be called by the mcount trampoline.
|
||||
*/
|
||||
static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip,
|
||||
static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *op, struct pt_regs *regs)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if ((op->flags & FTRACE_OPS_FL_RCU) && !rcu_is_watching())
|
||||
return;
|
||||
|
||||
bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX);
|
||||
if (bit < 0)
|
||||
return;
|
||||
|
||||
op->func(ip, parent_ip, op, regs);
|
||||
preempt_disable_notrace();
|
||||
|
||||
if (!(op->flags & FTRACE_OPS_FL_PER_CPU) ||
|
||||
!ftrace_function_local_disabled(op)) {
|
||||
op->func(ip, parent_ip, op, regs);
|
||||
}
|
||||
|
||||
preempt_enable_notrace();
|
||||
trace_clear_recursion(bit);
|
||||
}
|
||||
|
||||
|
@ -5262,12 +5268,12 @@ static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip,
|
|||
ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops)
|
||||
{
|
||||
/*
|
||||
* If the func handles its own recursion, call it directly.
|
||||
* Otherwise call the recursion protected function that
|
||||
* will call the ftrace ops function.
|
||||
* If the function does not handle recursion, needs to be RCU safe,
|
||||
* or does per cpu logic, then we need to call the assist handler.
|
||||
*/
|
||||
if (!(ops->flags & FTRACE_OPS_FL_RECURSION_SAFE))
|
||||
return ftrace_ops_recurs_func;
|
||||
if (!(ops->flags & FTRACE_OPS_FL_RECURSION_SAFE) ||
|
||||
ops->flags & (FTRACE_OPS_FL_RCU | FTRACE_OPS_FL_PER_CPU))
|
||||
return ftrace_ops_assist_func;
|
||||
|
||||
return ops->func;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue