aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-07-29 13:50:33 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-29 12:47:34 -0400
commit8169887b694aa3d9632fdd0308aaa1db7c422e75 (patch)
tree521d15d1f21cdcbbf25d490a3a0f850e31635fbe /kernel
parent012dc156d6af49e02a30fcba7d688e251608d97c (diff)
tracing: trace_remove_event_call() should fail if call/file is in use
commit 2816c551c796ec14620325b2c9ed75b9979d3125 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.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 0bff8aaf581b..3d18aadef493 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1735,16 +1735,47 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
1735 destroy_preds(call); 1735 destroy_preds(call);
1736} 1736}
1737 1737
1738static int probe_remove_event_call(struct ftrace_event_call *call)
1739{
1740 struct trace_array *tr;
1741 struct ftrace_event_file *file;
1742
1743#ifdef CONFIG_PERF_EVENTS
1744 if (call->perf_refcount)
1745 return -EBUSY;
1746#endif
1747 do_for_each_event_file(tr, file) {
1748 if (file->event_call != call)
1749 continue;
1750 /*
1751 * We can't rely on ftrace_event_enable_disable(enable => 0)
1752 * we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress
1753 * TRACE_REG_UNREGISTER.
1754 */
1755 if (file->flags & FTRACE_EVENT_FL_ENABLED)
1756 return -EBUSY;
1757 break;
1758 } while_for_each_event_file();
1759
1760 __trace_remove_event_call(call);
1761
1762 return 0;
1763}
1764
1738/* Remove an event_call */ 1765/* Remove an event_call */
1739void trace_remove_event_call(struct ftrace_event_call *call) 1766int trace_remove_event_call(struct ftrace_event_call *call)
1740{ 1767{
1768 int ret;
1769
1741 mutex_lock(&trace_types_lock); 1770 mutex_lock(&trace_types_lock);
1742 mutex_lock(&event_mutex); 1771 mutex_lock(&event_mutex);
1743 down_write(&trace_event_sem); 1772 down_write(&trace_event_sem);
1744 __trace_remove_event_call(call); 1773 ret = probe_remove_event_call(call);
1745 up_write(&trace_event_sem); 1774 up_write(&trace_event_sem);
1746 mutex_unlock(&event_mutex); 1775 mutex_unlock(&event_mutex);
1747 mutex_unlock(&trace_types_lock); 1776 mutex_unlock(&trace_types_lock);
1777
1778 return ret;
1748} 1779}
1749 1780
1750#define for_each_event(event, start, end) \ 1781#define for_each_event(event, start, end) \