aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-07-29 13:50:33 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-07-31 13:12:48 -0400
commit2816c551c796ec14620325b2c9ed75b9979d3125 (patch)
treec4bc262514de5ef265001411bcdf7ad65916eae9 /kernel
parent776164c1faac4966ab14418bb0922e1820da1d19 (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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace_events.c35
1 files changed, 33 insertions, 2 deletions
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
1716static 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 */
1717void trace_remove_event_call(struct ftrace_event_call *call) 1744int 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) \