tracing: Warn if a tracepoint is not set via debugfs
authorSteven Rostedt <rostedt@goodmis.org>
Thu, 13 Feb 2014 20:45:07 +0000 (15:45 -0500)
committerSteven Rostedt <rostedt@goodmis.org>
Fri, 7 Mar 2014 15:06:07 +0000 (10:06 -0500)
Tracepoints were made to allow enabling a tracepoint in a module before that
module was loaded. When a tracepoint is enabled and it does not exist, the
name is stored and will be enabled when the tracepoint is created.

The problem with this approach is that when a tracepoint is enabled when
it expects to be there, it gives no warning that it does not exist.

To add salt to the wound, if a module is added and sets the FORCED flag, which
can happen if it isn't signed properly, the tracepoint code will not enabled
the tracepoints, but they will be created in the debugfs system! When a user
goes to enable the tracepoint, the tracepoint code will not see it existing
and will think it is to be enabled later AND WILL NOT GIVE A WARNING.

The tracing will look like it succeeded but will actually be doing nothing.
This will cause lots of confusion and headaches for developers trying to
figure out why they are not seeing their tracepoints.

Link: http://lkml.kernel.org/r/20140213154507.4040fb06@gandalf.local.home
Reported-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Reported-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/tracepoint.c

index 0d4ef26..0058f33 100644 (file)
@@ -62,6 +62,7 @@ struct tracepoint_entry {
        struct hlist_node hlist;
        struct tracepoint_func *funcs;
        int refcount;   /* Number of times armed. 0 if disarmed. */
+       int enabled;    /* Tracepoint enabled */
        char name[0];
 };
 
@@ -237,6 +238,7 @@ static struct tracepoint_entry *add_tracepoint(const char *name)
        memcpy(&e->name[0], name, name_len);
        e->funcs = NULL;
        e->refcount = 0;
+       e->enabled = 0;
        hlist_add_head(&e->hlist, head);
        return e;
 }
@@ -316,6 +318,7 @@ static void tracepoint_update_probe_range(struct tracepoint * const *begin,
                if (mark_entry) {
                        set_tracepoint(&mark_entry, *iter,
                                        !!mark_entry->refcount);
+                       mark_entry->enabled = !!mark_entry->refcount;
                } else {
                        disable_tracepoint(*iter);
                }
@@ -380,6 +383,8 @@ tracepoint_add_probe(const char *name, void *probe, void *data)
 int tracepoint_probe_register(const char *name, void *probe, void *data)
 {
        struct tracepoint_func *old;
+       struct tracepoint_entry *entry;
+       int ret = 0;
 
        mutex_lock(&tracepoints_mutex);
        old = tracepoint_add_probe(name, probe, data);
@@ -388,9 +393,13 @@ int tracepoint_probe_register(const char *name, void *probe, void *data)
                return PTR_ERR(old);
        }
        tracepoint_update_probes();             /* may update entry */
+       entry = get_tracepoint(name);
+       /* Make sure the entry was enabled */
+       if (!entry || !entry->enabled)
+               ret = -ENODEV;
        mutex_unlock(&tracepoints_mutex);
        release_probes(old);
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_register);