ftrace: Have the cached module list show in set_ftrace_filter
authorSteven Rostedt (VMware) <rostedt@goodmis.org>
Fri, 23 Jun 2017 20:05:11 +0000 (16:05 -0400)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Mon, 26 Jun 2017 15:53:02 +0000 (11:53 -0400)
When writing in a module filter into set_ftrace_filter for a module that is
not yet loaded, it it cached, and will be executed when the module is loaded
(although that is not implemented yet at this commit). Display the list of
cached modules to be traced.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
include/linux/ftrace.h
kernel/trace/ftrace.c

index 1b6992e994e6a0242ee92016c17622be65f1fb58..9fb9a67dc9d4f2dfe2360d55d90792af8e20399d 100644 (file)
@@ -446,7 +446,8 @@ enum {
        FTRACE_ITER_PRINTALL    = (1 << 2),
        FTRACE_ITER_DO_PROBES   = (1 << 3),
        FTRACE_ITER_PROBE       = (1 << 4),
-       FTRACE_ITER_ENABLED     = (1 << 5),
+       FTRACE_ITER_MOD         = (1 << 5),
+       FTRACE_ITER_ENABLED     = (1 << 6),
 };
 
 void arch_ftrace_update_code(int command);
index 1867edec62697c7a8350deda612210ab052b588c..bfdbce78064b79da07f3d25eff86c8c104026721 100644 (file)
@@ -3112,6 +3112,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
 struct ftrace_iterator {
        loff_t                          pos;
        loff_t                          func_pos;
+       loff_t                          mod_pos;
        struct ftrace_page              *pg;
        struct dyn_ftrace               *func;
        struct ftrace_func_probe        *probe;
@@ -3119,6 +3120,8 @@ struct ftrace_iterator {
        struct trace_parser             parser;
        struct ftrace_hash              *hash;
        struct ftrace_ops               *ops;
+       struct trace_array              *tr;
+       struct list_head                *mod_list;
        int                             pidx;
        int                             idx;
        unsigned                        flags;
@@ -3203,13 +3206,13 @@ static void *t_probe_start(struct seq_file *m, loff_t *pos)
        if (!(iter->flags & FTRACE_ITER_DO_PROBES))
                return NULL;
 
-       if (iter->func_pos > *pos)
+       if (iter->mod_pos > *pos)
                return NULL;
 
        iter->probe = NULL;
        iter->probe_entry = NULL;
        iter->pidx = 0;
-       for (l = 0; l <= (*pos - iter->func_pos); ) {
+       for (l = 0; l <= (*pos - iter->mod_pos); ) {
                p = t_probe_next(m, &l);
                if (!p)
                        break;
@@ -3247,6 +3250,82 @@ t_probe_show(struct seq_file *m, struct ftrace_iterator *iter)
        return 0;
 }
 
+static void *
+t_mod_next(struct seq_file *m, loff_t *pos)
+{
+       struct ftrace_iterator *iter = m->private;
+       struct trace_array *tr = iter->tr;
+
+       (*pos)++;
+       iter->pos = *pos;
+
+       iter->mod_list = iter->mod_list->next;
+
+       if (iter->mod_list == &tr->mod_trace ||
+           iter->mod_list == &tr->mod_notrace) {
+               iter->flags &= ~FTRACE_ITER_MOD;
+               return NULL;
+       }
+
+       iter->mod_pos = *pos;
+
+       return iter;
+}
+
+static void *t_mod_start(struct seq_file *m, loff_t *pos)
+{
+       struct ftrace_iterator *iter = m->private;
+       void *p = NULL;
+       loff_t l;
+
+       if (iter->func_pos > *pos)
+               return NULL;
+
+       iter->mod_pos = iter->func_pos;
+
+       /* probes are only available if tr is set */
+       if (!iter->tr)
+               return NULL;
+
+       for (l = 0; l <= (*pos - iter->func_pos); ) {
+               p = t_mod_next(m, &l);
+               if (!p)
+                       break;
+       }
+       if (!p) {
+               iter->flags &= ~FTRACE_ITER_MOD;
+               return t_probe_start(m, pos);
+       }
+
+       /* Only set this if we have an item */
+       iter->flags |= FTRACE_ITER_MOD;
+
+       return iter;
+}
+
+static int
+t_mod_show(struct seq_file *m, struct ftrace_iterator *iter)
+{
+       struct ftrace_mod_load *ftrace_mod;
+       struct trace_array *tr = iter->tr;
+
+       if (WARN_ON_ONCE(!iter->mod_list) ||
+                        iter->mod_list == &tr->mod_trace ||
+                        iter->mod_list == &tr->mod_notrace)
+               return -EIO;
+
+       ftrace_mod = list_entry(iter->mod_list, struct ftrace_mod_load, list);
+
+       if (ftrace_mod->func)
+               seq_printf(m, "%s", ftrace_mod->func);
+       else
+               seq_putc(m, '*');
+
+       seq_printf(m, ":mod:%s\n", ftrace_mod->module);
+
+       return 0;
+}
+
 static void *
 t_func_next(struct seq_file *m, loff_t *pos)
 {
@@ -3288,7 +3367,7 @@ static void *
 t_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
-       loff_t l = *pos; /* t_hash_start() must use original pos */
+       loff_t l = *pos; /* t_probe_start() must use original pos */
        void *ret;
 
        if (unlikely(ftrace_disabled))
@@ -3297,16 +3376,19 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
        if (iter->flags & FTRACE_ITER_PROBE)
                return t_probe_next(m, pos);
 
+       if (iter->flags & FTRACE_ITER_MOD)
+               return t_mod_next(m, pos);
+
        if (iter->flags & FTRACE_ITER_PRINTALL) {
                /* next must increment pos, and t_probe_start does not */
                (*pos)++;
-               return t_probe_start(m, &l);
+               return t_mod_start(m, &l);
        }
 
        ret = t_func_next(m, pos);
 
        if (!ret)
-               return t_probe_start(m, &l);
+               return t_mod_start(m, &l);
 
        return ret;
 }
@@ -3315,7 +3397,7 @@ static void reset_iter_read(struct ftrace_iterator *iter)
 {
        iter->pos = 0;
        iter->func_pos = 0;
-       iter->flags &= ~(FTRACE_ITER_PRINTALL | FTRACE_ITER_PROBE);
+       iter->flags &= ~(FTRACE_ITER_PRINTALL | FTRACE_ITER_PROBE | FTRACE_ITER_MOD);
 }
 
 static void *t_start(struct seq_file *m, loff_t *pos)
@@ -3344,15 +3426,15 @@ static void *t_start(struct seq_file *m, loff_t *pos)
            ftrace_hash_empty(iter->hash)) {
                iter->func_pos = 1; /* Account for the message */
                if (*pos > 0)
-                       return t_probe_start(m, pos);
+                       return t_mod_start(m, pos);
                iter->flags |= FTRACE_ITER_PRINTALL;
                /* reset in case of seek/pread */
                iter->flags &= ~FTRACE_ITER_PROBE;
                return iter;
        }
 
-       if (iter->flags & FTRACE_ITER_PROBE)
-               return t_probe_start(m, pos);
+       if (iter->flags & FTRACE_ITER_MOD)
+               return t_mod_start(m, pos);
 
        /*
         * Unfortunately, we need to restart at ftrace_pages_start
@@ -3368,7 +3450,7 @@ static void *t_start(struct seq_file *m, loff_t *pos)
        }
 
        if (!p)
-               return t_probe_start(m, pos);
+               return t_mod_start(m, pos);
 
        return iter;
 }
@@ -3402,6 +3484,9 @@ static int t_show(struct seq_file *m, void *v)
        if (iter->flags & FTRACE_ITER_PROBE)
                return t_probe_show(m, iter);
 
+       if (iter->flags & FTRACE_ITER_MOD)
+               return t_mod_show(m, iter);
+
        if (iter->flags & FTRACE_ITER_PRINTALL) {
                if (iter->flags & FTRACE_ITER_NOTRACE)
                        seq_puts(m, "#### no functions disabled ####\n");
@@ -3528,17 +3613,20 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
 
        iter->ops = ops;
        iter->flags = flag;
+       iter->tr = tr;
 
        mutex_lock(&ops->func_hash->regex_lock);
 
        if (flag & FTRACE_ITER_NOTRACE) {
                hash = ops->func_hash->notrace_hash;
-               mod_head = tr ? &tr->mod_trace : NULL;
+               mod_head = tr ? &tr->mod_notrace : NULL;
        } else {
                hash = ops->func_hash->filter_hash;
-               mod_head = tr ? &tr->mod_notrace : NULL;
+               mod_head = tr ? &tr->mod_trace : NULL;
        }
 
+       iter->mod_list = mod_head;
+
        if (file->f_mode & FMODE_WRITE) {
                const int size_bits = FTRACE_HASH_DEFAULT_BITS;