diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-29 13:50:33 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-07-31 13:12:48 -0400 |
commit | 2816c551c796ec14620325b2c9ed75b9979d3125 (patch) | |
tree | c4bc262514de5ef265001411bcdf7ad65916eae9 | |
parent | 776164c1faac4966ab14418bb0922e1820da1d19 (diff) |
tracing: trace_remove_event_call() should fail if call/file is in use
Change trace_remove_event_call(call) to return the error if this
call is active. This is what the callers assume but can't verify
outside of the tracing locks. Both trace_kprobe.c/trace_uprobe.c
need the additional changes, unregister_trace_probe() should abort
if trace_remove_event_call() fails.
The caller is going to free this call/file so we must ensure that
nobody can use them after trace_remove_event_call() succeeds.
debugfs should be fine after the previous changes and event_remove()
does TRACE_REG_UNREGISTER, but still there are 2 reasons why we need
the additional checks:
- There could be a perf_event(s) attached to this tp_event, so the
patch checks ->perf_refcount.
- TRACE_REG_UNREGISTER can be suppressed by FTRACE_EVENT_FL_SOFT_MODE,
so we simply check FTRACE_EVENT_FL_ENABLED protected by event_mutex.
Link: http://lkml.kernel.org/r/20130729175033.GB26284@redhat.com
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | include/linux/ftrace_event.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 35 |
2 files changed, 34 insertions, 3 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 4372658c73ae..f98ab063e95e 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -332,7 +332,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
332 | const char *name, int offset, int size, | 332 | const char *name, int offset, int size, |
333 | int is_signed, int filter_type); | 333 | int is_signed, int filter_type); |
334 | extern int trace_add_event_call(struct ftrace_event_call *call); | 334 | extern int trace_add_event_call(struct ftrace_event_call *call); |
335 | extern void trace_remove_event_call(struct ftrace_event_call *call); | 335 | extern int trace_remove_event_call(struct ftrace_event_call *call); |
336 | 336 | ||
337 | #define is_signed_type(type) (((type)(-1)) < (type)1) | 337 | #define is_signed_type(type) (((type)(-1)) < (type)1) |
338 | 338 | ||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index a67c913e2f9f..ec04836273c0 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -1713,16 +1713,47 @@ static void __trace_remove_event_call(struct ftrace_event_call *call) | |||
1713 | destroy_preds(call); | 1713 | destroy_preds(call); |
1714 | } | 1714 | } |
1715 | 1715 | ||
1716 | static int probe_remove_event_call(struct ftrace_event_call *call) | ||
1717 | { | ||
1718 | struct trace_array *tr; | ||
1719 | struct ftrace_event_file *file; | ||
1720 | |||
1721 | #ifdef CONFIG_PERF_EVENTS | ||
1722 | if (call->perf_refcount) | ||
1723 | return -EBUSY; | ||
1724 | #endif | ||
1725 | do_for_each_event_file(tr, file) { | ||
1726 | if (file->event_call != call) | ||
1727 | continue; | ||
1728 | /* | ||
1729 | * We can't rely on ftrace_event_enable_disable(enable => 0) | ||
1730 | * we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress | ||
1731 | * TRACE_REG_UNREGISTER. | ||
1732 | */ | ||
1733 | if (file->flags & FTRACE_EVENT_FL_ENABLED) | ||
1734 | return -EBUSY; | ||
1735 | break; | ||
1736 | } while_for_each_event_file(); | ||
1737 | |||
1738 | __trace_remove_event_call(call); | ||
1739 | |||
1740 | return 0; | ||
1741 | } | ||
1742 | |||
1716 | /* Remove an event_call */ | 1743 | /* Remove an event_call */ |
1717 | void trace_remove_event_call(struct ftrace_event_call *call) | 1744 | int trace_remove_event_call(struct ftrace_event_call *call) |
1718 | { | 1745 | { |
1746 | int ret; | ||
1747 | |||
1719 | mutex_lock(&trace_types_lock); | 1748 | mutex_lock(&trace_types_lock); |
1720 | mutex_lock(&event_mutex); | 1749 | mutex_lock(&event_mutex); |
1721 | down_write(&trace_event_sem); | 1750 | down_write(&trace_event_sem); |
1722 | __trace_remove_event_call(call); | 1751 | ret = probe_remove_event_call(call); |
1723 | up_write(&trace_event_sem); | 1752 | up_write(&trace_event_sem); |
1724 | mutex_unlock(&event_mutex); | 1753 | mutex_unlock(&event_mutex); |
1725 | mutex_unlock(&trace_types_lock); | 1754 | mutex_unlock(&trace_types_lock); |
1755 | |||
1756 | return ret; | ||
1726 | } | 1757 | } |
1727 | 1758 | ||
1728 | #define for_each_event(event, start, end) \ | 1759 | #define for_each_event(event, start, end) \ |