Messages in this thread |  | | Subject | Re: [PATCH 4/9] ftrace: Add enable/disable ftrace_ops control interface | | From | Steven Rostedt <> | | Date | Mon, 28 Nov 2011 14:26:38 -0500 |
| |
[ Added Peter Z ]
On Sun, 2011-11-27 at 19:04 +0100, Jiri Olsa wrote: > Adding a way to temporarily enable/disable ftrace_ops. > > When there is a ftrace_ops with FTRACE_OPS_FL_CONTROL flag > registered, the ftrace_ops_list_func processing function > is used as ftrace function in order to have all registered > ftrace_ops under control. > > Also using jump label not to introduce overhead to current > ftrace_ops_list_func processing. >
Are jump labels safe in NMI context yet? If not, this will need to wait till we make it so.
-- Steve
> Signed-off-by: Jiri Olsa <jolsa@redhat.com> > --- > include/linux/ftrace.h | 12 ++++++++++++ > kernel/trace/ftrace.c | 39 +++++++++++++++++++++++++++++---------- > 2 files changed, 41 insertions(+), 10 deletions(-) > > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h > index 26eafce..28b59f1 100644 > --- a/include/linux/ftrace.h > +++ b/include/linux/ftrace.h > @@ -35,12 +35,14 @@ enum { > FTRACE_OPS_FL_ENABLED = 1 << 0, > FTRACE_OPS_FL_GLOBAL = 1 << 1, > FTRACE_OPS_FL_DYNAMIC = 1 << 2, > + FTRACE_OPS_FL_CONTROL = 1 << 3, > }; > > struct ftrace_ops { > ftrace_func_t func; > struct ftrace_ops *next; > unsigned long flags; > + atomic_t disabled; > #ifdef CONFIG_DYNAMIC_FTRACE > struct ftrace_hash *notrace_hash; > struct ftrace_hash *filter_hash; > @@ -97,6 +99,16 @@ int register_ftrace_function(struct ftrace_ops *ops); > int unregister_ftrace_function(struct ftrace_ops *ops); > void clear_ftrace_function(void); > > +static inline void enable_ftrace_function(struct ftrace_ops *ops) > +{ > + atomic_dec(&ops->disabled); > +} > + > +static inline void disable_ftrace_function(struct ftrace_ops *ops) > +{ > + atomic_inc(&ops->disabled); > +} > + > extern void ftrace_stub(unsigned long a0, unsigned long a1); > > #else /* !CONFIG_FUNCTION_TRACER */ > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c > index 0ca0c0d..e5a9498 100644 > --- a/kernel/trace/ftrace.c > +++ b/kernel/trace/ftrace.c > @@ -30,6 +30,7 @@ > #include <linux/list.h> > #include <linux/hash.h> > #include <linux/rcupdate.h> > +#include <linux/jump_label.h> > > #include <trace/events/sched.h> > > @@ -94,6 +95,8 @@ ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; > ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; > static struct ftrace_ops global_ops; > > +static struct jump_label_key ftrace_ops_control; > + > static void > ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); > > @@ -196,17 +199,21 @@ static void update_ftrace_function(void) > > update_global_ops(); > > - /* > - * If we are at the end of the list and this ops is > - * not dynamic, then have the mcount trampoline call > - * the function directly > - */ > - if (ftrace_ops_list == &ftrace_list_end || > - (ftrace_ops_list->next == &ftrace_list_end && > - !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC))) > - func = ftrace_ops_list->func; > - else > + if (jump_label_enabled(&ftrace_ops_control)) > func = ftrace_ops_list_func; > + else { > + /* > + * If we are at the end of the list and this ops is > + * not dynamic, then have the mcount trampoline call > + * the function directly > + */ > + if (ftrace_ops_list == &ftrace_list_end || > + (ftrace_ops_list->next == &ftrace_list_end && > + !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC))) > + func = ftrace_ops_list->func; > + else > + func = ftrace_ops_list_func; > + } > > #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST > ftrace_trace_function = func; > @@ -280,6 +287,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops) > } else > add_ftrace_ops(&ftrace_ops_list, ops); > > + if (ops->flags & FTRACE_OPS_FL_CONTROL) > + jump_label_inc(&ftrace_ops_control); > + > if (ftrace_enabled) > update_ftrace_function(); > > @@ -311,6 +321,9 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) > if (ret < 0) > return ret; > > + if (ops->flags & FTRACE_OPS_FL_CONTROL) > + jump_label_dec(&ftrace_ops_control); > + > if (ftrace_enabled) > update_ftrace_function(); > > @@ -3577,8 +3590,14 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) > preempt_disable_notrace(); > op = rcu_dereference_raw(ftrace_ops_list); > while (op != &ftrace_list_end) { > + if (static_branch(&ftrace_ops_control)) > + if ((op->flags & FTRACE_OPS_FL_CONTROL) && > + atomic_read(&op->disabled)) > + goto next; > + > if (ftrace_ops_test(op, ip)) > op->func(ip, parent_ip); > + next: > op = rcu_dereference_raw(op->next); > }; > preempt_enable_notrace();
|  |