tracing: add protection around module events unload
authorSteven Rostedt <srostedt@redhat.com>
Tue, 9 Jun 2009 21:29:07 +0000 (17:29 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Tue, 9 Jun 2009 21:29:07 +0000 (17:29 -0400)
When reading the trace buffer, there is a race that when a module
is unloaded it removes events that is stilled referenced in the buffers.
This patch adds the protection around the unloading of the events
from modules and the reading of the trace buffers.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/trace/trace_events.c
kernel/trace/trace_output.c
kernel/trace/trace_output.h

index 6c81f9c21426f366d6301a208f7ed37c8572e5da..aa08be69a1b6c1fcc026359ece8613812ad1a492 100644 (file)
@@ -1050,12 +1050,13 @@ static void trace_module_remove_events(struct module *mod)
        struct ftrace_event_call *call, *p;
        bool found = false;
 
+       down_write(&trace_event_mutex);
        list_for_each_entry_safe(call, p, &ftrace_events, list) {
                if (call->mod == mod) {
                        found = true;
                        ftrace_event_enable_disable(call, 0);
                        if (call->event)
-                               unregister_ftrace_event(call->event);
+                               __unregister_ftrace_event(call->event);
                        debugfs_remove_recursive(call->dir);
                        list_del(&call->list);
                        trace_destroy_fields(call);
@@ -1079,6 +1080,7 @@ static void trace_module_remove_events(struct module *mod)
         */
        if (found)
                tracing_reset_current_online_cpus();
+       up_write(&trace_event_mutex);
 }
 
 static int trace_module_notify(struct notifier_block *self,
index c05aff465dc9110b562c47c0905a0e6e048a8ee3..7938f3ae93e3dbe9d898e037c47027c4908a8d94 100644 (file)
@@ -14,7 +14,7 @@
 /* must be a power of 2 */
 #define EVENT_HASHSIZE 128
 
-static DECLARE_RWSEM(trace_event_mutex);
+DECLARE_RWSEM(trace_event_mutex);
 
 DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
 EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
@@ -702,6 +702,16 @@ int register_ftrace_event(struct trace_event *event)
 }
 EXPORT_SYMBOL_GPL(register_ftrace_event);
 
+/*
+ * Used by module code with the trace_event_mutex held for write.
+ */
+int __unregister_ftrace_event(struct trace_event *event)
+{
+       hlist_del(&event->node);
+       list_del(&event->list);
+       return 0;
+}
+
 /**
  * unregister_ftrace_event - remove a no longer used event
  * @event: the event to remove
@@ -709,8 +719,7 @@ EXPORT_SYMBOL_GPL(register_ftrace_event);
 int unregister_ftrace_event(struct trace_event *event)
 {
        down_write(&trace_event_mutex);
-       hlist_del(&event->node);
-       list_del(&event->list);
+       __unregister_ftrace_event(event);
        up_write(&trace_event_mutex);
 
        return 0;
index ac240e76eb012d9f9068ff93dc3eed8e05a23787..d38bec4a9c3081e52bca0dec51e04e94827cba67 100644 (file)
@@ -27,6 +27,10 @@ extern struct trace_event *ftrace_find_event(int type);
 extern enum print_line_t trace_nop_print(struct trace_iterator *iter,
                                         int flags);
 
+/* used by module unregistering */
+extern int __unregister_ftrace_event(struct trace_event *event);
+extern struct rw_semaphore trace_event_mutex;
+
 #define MAX_MEMHEX_BYTES       8
 #define HEX_CHARS              (MAX_MEMHEX_BYTES*2 + 1)