This new macro allows to hook conditional tracepoint probes to
pre-existing trace events. This allows to create specialized versions of
the same tracepoint without having to explicitly call every possible
tracepoints in the instrumented code.

In order to use it, a TRACE_EVENT must already exist, after that, we can
connect as many TRACE_EVENT_MAP_COND to this TRACE_EVENT as needed.

Example usage:

TRACE_EVENT(tp_test,
        TP_PROTO(proto),
        TP_ARGS(args),
        TP_STRUCT__entry(), /* can be empty */
        TP_fast_assign(), /* can be empty */
        TP_printk() /* can be empty */
);

TRACE_EVENT_MAP_COND(tp_test, cond_test,
        TP_PROTO(proto),
        TP_ARGS(args),
        TP_CONDITION(cond),
        TP_STRUCT__entry(entry),
        TP_fast_assign(assign),
        TP_printk(print)
);

Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Steven Rostedt (Red Hat) <rost...@goodmis.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Ingo Molnar <mi...@redhat.com>
Cc: Daniel Bristot de Oliveira <bris...@redhat.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoy...@efficios.com>
Signed-off-by: Julien Desfossez <jdesfos...@efficios.com>
---
 include/linux/trace_events.h |  14 ++++-
 include/linux/tracepoint.h   |   6 ++
 include/trace/define_trace.h |   6 ++
 include/trace/perf.h         |  24 ++++++--
 include/trace/trace_events.h | 130 +++++++++++++++++++++++++++++++++++++------
 kernel/trace/trace_events.c  |  15 +++--
 6 files changed, 168 insertions(+), 27 deletions(-)

diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index be00761..1f7e0ec 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -217,6 +217,7 @@ enum {
        TRACE_EVENT_FL_TRACEPOINT_BIT,
        TRACE_EVENT_FL_KPROBE_BIT,
        TRACE_EVENT_FL_UPROBE_BIT,
+       TRACE_EVENT_FL_MAP_BIT,
 };
 
 /*
@@ -231,6 +232,7 @@ enum {
  *  TRACEPOINT    - Event is a tracepoint
  *  KPROBE        - Event is a kprobe
  *  UPROBE        - Event is a uprobe
+ *  MAP           - Event maps to a tracepoint as an alias
  */
 enum {
        TRACE_EVENT_FL_FILTERED         = (1 << TRACE_EVENT_FL_FILTERED_BIT),
@@ -241,10 +243,16 @@ enum {
        TRACE_EVENT_FL_TRACEPOINT       = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
        TRACE_EVENT_FL_KPROBE           = (1 << TRACE_EVENT_FL_KPROBE_BIT),
        TRACE_EVENT_FL_UPROBE           = (1 << TRACE_EVENT_FL_UPROBE_BIT),
+       TRACE_EVENT_FL_MAP              = (1 << TRACE_EVENT_FL_MAP_BIT),
 };
 
 #define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE)
 
+struct trace_event_map {
+       struct tracepoint       *tp;
+       char                    *name;
+};
+
 struct trace_event_call {
        struct list_head        list;
        struct trace_event_class *class;
@@ -252,6 +260,8 @@ struct trace_event_call {
                char                    *name;
                /* Set TRACE_EVENT_FL_TRACEPOINT flag when using "tp" */
                struct tracepoint       *tp;
+               /* Set TRACE_EVENT_FL_MAP flag when using "map" instead */
+               struct trace_event_map  *map;
        };
        struct trace_event      event;
        char                    *print_fmt;
@@ -282,7 +292,9 @@ struct trace_event_call {
 static inline const char *
 trace_event_name(struct trace_event_call *call)
 {
-       if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
+       if (call->flags & TRACE_EVENT_FL_MAP)
+               return call->map->name;
+       else if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
                return call->tp ? call->tp->name : NULL;
        else
                return call->name;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index f72fcfe..3e5b5a4 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -276,6 +276,7 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define DEFINE_TRACE_FN(name, reg, unreg)
 #define DEFINE_TRACE(name)
+#define DEFINE_TRACE_MAP_COND(name, map, cond)
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
@@ -469,6 +470,8 @@ static inline void tracepoint_synchronize_unregister(void)
  */
 
 #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print)
+#define DECLARE_EVENT_COND_CLASS(name, proto, args, cond,      \
+               tstruct, assign, print)
 #define DEFINE_EVENT(template, name, proto, args)              \
        DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
 #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)\
@@ -498,4 +501,7 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define TRACE_EVENT_PERF_PERM(event, expr...)
 
+#define TRACE_EVENT_MAP_COND(name, map, proto, args, cond,     \
+               struct, assign, print)
+
 #endif /* ifdef TRACE_EVENT (see note above) */
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index 6e3945f..4e112f2 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -45,6 +45,10 @@
                assign, print, reg, unreg)                      \
        DEFINE_TRACE_FN(name, reg, unreg)
 
+#undef TRACE_EVENT_MAP_COND
+#define TRACE_EVENT_MAP_COND(name, map, proto, args, cond, tstruct,    \
+               assign, print)
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args) \
        DEFINE_TRACE(name)
@@ -100,7 +104,9 @@
 #undef TRACE_EVENT_FN
 #undef TRACE_EVENT_FN_COND
 #undef TRACE_EVENT_CONDITION
+#undef TRACE_EVENT_MAP_COND
 #undef DECLARE_EVENT_CLASS
+#undef DECLARE_EVENT_COND_CLASS
 #undef DEFINE_EVENT
 #undef DEFINE_EVENT_FN
 #undef DEFINE_EVENT_PRINT
diff --git a/include/trace/perf.h b/include/trace/perf.h
index 04fe68bb..dbd3d27 100644
--- a/include/trace/perf.h
+++ b/include/trace/perf.h
@@ -26,8 +26,9 @@
 #undef __perf_task
 #define __perf_task(t) (__task = (t))
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
 static notrace void                                                    \
 perf_trace_##call(void *__data, proto)                                 \
 {                                                                      \
@@ -43,6 +44,9 @@
        int __data_size;                                                \
        int rctx;                                                       \
                                                                        \
+       if (!(cond))                                                    \
+               return;                                                 \
+                                                                       \
        __data_size = trace_event_get_offsets_##call(&__data_offsets, args); \
                                                                        \
        head = this_cpu_ptr(event_call->perf_events);                   \
@@ -69,18 +73,28 @@
                                  head, __task);                        \
 }
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args),     \
+                       1, PARAMS(tstruct), PARAMS(assign),             \
+                       PARAMS(print))
+
 /*
  * This part is compiled out, it is only here as a build time check
  * to make sure that if the tracepoint handling changes, the
  * perf probe will fail to compile unless it too is updated.
  */
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, call, proto, args)                      \
-static inline void perf_test_probe_##call(void)                                
\
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, call, map, proto, args, cond)  \
+static inline void perf_test_probe_##map(void)                         \
 {                                                                      \
        check_trace_callback_type_##call(perf_trace_##template);        \
 }
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+       DEFINE_EVENT_MAP_COND(template, call, call, PARAMS(proto),      \
+                       PARAMS(args), 1)
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
diff --git a/include/trace/trace_events.h b/include/trace/trace_events.h
index 467e12f..953cea3 100644
--- a/include/trace/trace_events.h
+++ b/include/trace/trace_events.h
@@ -65,6 +65,18 @@
                             PARAMS(print));                   \
        DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
 
+#undef TRACE_EVENT_MAP_COND
+#define TRACE_EVENT_MAP_COND(name, map, proto, args, cond,     \
+               tstruct, assign, print)                         \
+       DECLARE_EVENT_COND_CLASS(map,                           \
+                       PARAMS(proto),                          \
+                       PARAMS(args),                           \
+                       PARAMS(cond),                           \
+                       PARAMS(tstruct),                        \
+                       PARAMS(assign),                         \
+                       PARAMS(print));                         \
+       DEFINE_EVENT_MAP_COND(map, name, map, PARAMS(proto),    \
+                       PARAMS(args), cond);
 
 #undef __field
 #define __field(type, item)            type    item;
@@ -93,8 +105,9 @@
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(name, proto, args, cond, tstruct,     \
+               assign, print)                                          \
        struct trace_event_raw_##name {                                 \
                struct trace_entry      ent;                            \
                tstruct                                                 \
@@ -103,6 +116,11 @@
                                                                        \
        static struct trace_event_class event_class_##name;
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(name, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)      \
        static struct trace_event_call  __used          \
@@ -116,6 +134,9 @@
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
 
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, name, map, proto, args, cond)
+
 /* Callbacks are meaningless to ftrace. */
 #undef TRACE_EVENT_FN
 #define TRACE_EVENT_FN(name, proto, args, tstruct,                     \
@@ -182,12 +203,18 @@
 #undef __bitmask
 #define __bitmask(item, nr_bits) __dynamic_array(unsigned long, item, -1)
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
        struct trace_event_data_offsets_##call {                        \
                tstruct;                                                \
        };
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
@@ -195,6 +222,9 @@
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
 
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, name, map, proto, args, cond)
+
 #undef TRACE_EVENT_FLAGS
 #define TRACE_EVENT_FLAGS(event, flag)
 
@@ -307,8 +337,9 @@
                trace_print_array_seq(p, array, count, el_size);        \
        })
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
 static notrace enum print_line_t                                       \
 trace_raw_output_##call(struct trace_iterator *iter, int flags,                
\
                        struct trace_event *trace_event)                \
@@ -332,6 +363,11 @@
        .trace                  = trace_raw_output_##call,              \
 };
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
 static notrace enum print_line_t                                       \
@@ -410,8 +446,9 @@
 #undef __bitmask
 #define __bitmask(item, nr_bits) __dynamic_array(unsigned long, item, -1)
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)   \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               func, print)                                            \
 static int notrace __init                                              \
 trace_event_define_fields_##call(struct trace_event_call *event_call)  \
 {                                                                      \
@@ -423,6 +460,11 @@
        return ret;                                                     \
 }
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)   \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(func), PARAMS(print))
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
@@ -430,6 +472,9 @@
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
 
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, name, map, proto, args, cond)
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
@@ -489,8 +534,9 @@
 #define __bitmask(item, nr_bits) __dynamic_array(unsigned long, item,  \
                                         __bitmask_size_in_longs(nr_bits))
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
 static inline notrace int trace_event_get_offsets_##call(              \
        struct trace_event_data_offsets_##call *__data_offsets, proto)  \
 {                                                                      \
@@ -503,6 +549,11 @@
        return __data_size;                                             \
 }
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
@@ -510,6 +561,9 @@
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
 
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, name, map, proto, args, cond)
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
@@ -658,8 +712,9 @@
 #undef __perf_task
 #define __perf_task(t) (t)
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
                                                                        \
 static notrace void                                                    \
 trace_event_raw_event_##call(void *__data, proto)                      \
@@ -670,6 +725,9 @@
        struct trace_event_raw_##call *entry;                           \
        int __data_size;                                                \
                                                                        \
+       if (!(cond))                                                    \
+               return;                                                 \
+                                                                       \
        if (trace_trigger_soft_disabled(trace_file))                    \
                return;                                                 \
                                                                        \
@@ -687,19 +745,30 @@
                                                                        \
        trace_event_buffer_commit(&fbuffer);                            \
 }
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 /*
  * The ftrace_test_probe is compiled out, it is only here as a build time check
  * to make sure that if the tracepoint handling changes, the ftrace probe will
  * fail to compile unless it too is updated.
  */
 
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, call, proto, args)                      \
-static inline void ftrace_test_probe_##call(void)                      \
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(template, call, map, proto, args, cond)  \
+        static inline void ftrace_test_probe_##map(void)               \
 {                                                                      \
        check_trace_callback_type_##call(trace_event_raw_event_##template); \
 }
 
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+        DEFINE_EVENT_MAP_COND(template, call, call, PARAMS(proto),     \
+                        PARAMS(args), 1)
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print)
 
@@ -720,8 +789,9 @@
 #undef TP_printk
 #define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
 
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+#undef DECLARE_EVENT_COND_CLASS
+#define DECLARE_EVENT_COND_CLASS(call, proto, args, cond, tstruct,     \
+               assign, print)                                          \
 _TRACE_PERF_PROTO(call, PARAMS(proto));                                        
\
 static char print_fmt_##call[] = print;                                        
\
 static struct trace_event_class __used __refdata event_class_##call = { \
@@ -734,6 +804,11 @@
        _TRACE_PERF_INIT(call)                                          \
 };
 
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_COND_CLASS(call, PARAMS(proto), PARAMS(args), 1,  \
+                       PARAMS(tstruct), PARAMS(assign), PARAMS(print))
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
                                                                        \
@@ -766,4 +841,25 @@
 static struct trace_event_call __used                                  \
 __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
+#undef DEFINE_EVENT_MAP_COND
+#define DEFINE_EVENT_MAP_COND(_template, _call, _map, _proto, _args, cond) \
+                                                                       \
+static struct trace_event_map event_map_##_map = {                     \
+       .tp = &__tracepoint_##_call,                                    \
+       .name = #_map,                                                  \
+};                                                                     \
+                                                                       \
+static struct trace_event_call __used event_##_map = {                 \
+       .class                  = &event_class_##_template,             \
+       {                                                               \
+               .map                    = &event_map_##_map,            \
+       },                                                              \
+       .event.funcs            = &trace_event_type_funcs_##_template,  \
+       .print_fmt              = print_fmt_##_template,                        
\
+       .flags                  = TRACE_EVENT_FL_TRACEPOINT | 
TRACE_EVENT_FL_MAP, \
+};                                                                     \
+static struct trace_event_call __used                                  \
+__attribute__((section("_ftrace_events"))) *__event_##_map = &event_##_map
+
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 9311654..b4ea2bf 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -287,26 +287,33 @@ int trace_event_reg(struct trace_event_call *call,
                    enum trace_reg type, void *data)
 {
        struct trace_event_file *file = data;
+       struct tracepoint *tp;
 
        WARN_ON(!(call->flags & TRACE_EVENT_FL_TRACEPOINT));
+
+       if (call->flags & TRACE_EVENT_FL_MAP)
+               tp = call->map->tp;
+       else
+               tp = call->tp;
+
        switch (type) {
        case TRACE_REG_REGISTER:
-               return tracepoint_probe_register(call->tp,
+               return tracepoint_probe_register(tp,
                                                 call->class->probe,
                                                 file);
        case TRACE_REG_UNREGISTER:
-               tracepoint_probe_unregister(call->tp,
+               tracepoint_probe_unregister(tp,
                                            call->class->probe,
                                            file);
                return 0;
 
 #ifdef CONFIG_PERF_EVENTS
        case TRACE_REG_PERF_REGISTER:
-               return tracepoint_probe_register(call->tp,
+               return tracepoint_probe_register(tp,
                                                 call->class->perf_probe,
                                                 call);
        case TRACE_REG_PERF_UNREGISTER:
-               tracepoint_probe_unregister(call->tp,
+               tracepoint_probe_unregister(tp,
                                            call->class->perf_probe,
                                            call);
                return 0;
-- 
1.9.1

Reply via email to