From: "Steven Rostedt (VMware)" <rost...@goodmis.org>

Signed-off-by: Steven Rostedt (VMware) <rost...@goodmis.org>
---
 include/linux/tracepoint-defs.h |  3 ++
 include/linux/tracepoint.h      | 65 ++++++++++++++++++++++-----------
 include/trace/define_trace.h    | 14 +++----
 kernel/tracepoint.c             | 29 +++++++++++++--
 4 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index 22c5a46e9693..a9d267be98de 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -11,6 +11,8 @@
 #include <linux/atomic.h>
 #include <linux/static_key.h>
 
+struct dynfunc_struct;
+
 struct trace_print_flags {
        unsigned long           mask;
        const char              *name;
@@ -30,6 +32,7 @@ struct tracepoint_func {
 struct tracepoint {
        const char *name;               /* Tracepoint name */
        struct static_key key;
+       struct dynfunc_struct *dynfunc;
        int (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 041f7e56a289..800c1b025e1f 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -21,6 +21,7 @@
 #include <linux/cpumask.h>
 #include <linux/rcupdate.h>
 #include <linux/tracepoint-defs.h>
+#include <linux/jump_function.h>
 
 struct module;
 struct tracepoint;
@@ -94,7 +95,9 @@ extern int syscall_regfunc(void);
 extern void syscall_unregfunc(void);
 #endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */
 
+#ifndef PARAMS
 #define PARAMS(args...) args
+#endif
 
 #define TRACE_DEFINE_ENUM(x)
 #define TRACE_DEFINE_SIZEOF(x)
@@ -138,12 +141,11 @@ extern void syscall_unregfunc(void);
  * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
  * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
  */
-#define __DO_TRACE(tp, proto, args, cond, rcuidle)                     \
+#define __DO_TRACE(name, proto, args, cond, rcuidle)                   \
        do {                                                            \
                struct tracepoint_func *it_func_ptr;                    \
-               void *it_func;                                          \
-               void *__data;                                           \
                int __maybe_unused idx = 0;                             \
+               void *__data;                                           \
                                                                        \
                if (!(cond))                                            \
                        return;                                         \
@@ -163,14 +165,11 @@ extern void syscall_unregfunc(void);
                        rcu_irq_enter_irqson();                         \
                }                                                       \
                                                                        \
-               it_func_ptr = rcu_dereference_raw((tp)->funcs);         \
-                                                                       \
+               it_func_ptr =                                           \
+                       rcu_dereference_raw((&__tracepoint_##name)->funcs); \
                if (it_func_ptr) {                                      \
-                       do {                                            \
-                               it_func = (it_func_ptr)->func;          \
-                               __data = (it_func_ptr)->data;           \
-                               ((void(*)(proto))(it_func))(args);      \
-                       } while ((++it_func_ptr)->func);                \
+                       __data = (it_func_ptr)->data;                   \
+                       dynfunc_tp_func_##name(args);                   \
                }                                                       \
                                                                        \
                if (rcuidle) {                                          \
@@ -186,7 +185,7 @@ extern void syscall_unregfunc(void);
        static inline void trace_##name##_rcuidle(proto)                \
        {                                                               \
                if (static_key_false(&__tracepoint_##name.key))         \
-                       __DO_TRACE(&__tracepoint_##name,                \
+                       __DO_TRACE(name,                                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond), 1);                 \
@@ -208,11 +207,13 @@ extern void syscall_unregfunc(void);
  * poking RCU a bit.
  */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
+       DECLARE_DYNAMIC_FUNCTION(tp_func_##name, PARAMS(data_proto),    \
+                                PARAMS(data_args));                    \
        extern struct tracepoint __tracepoint_##name;                   \
        static inline void trace_##name(proto)                          \
        {                                                               \
                if (static_key_false(&__tracepoint_##name.key))         \
-                       __DO_TRACE(&__tracepoint_##name,                \
+                       __DO_TRACE(name,                                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond), 0);                 \
@@ -271,21 +272,43 @@ extern void syscall_unregfunc(void);
  * structures, so we create an array of pointers that will be used for 
iteration
  * on the tracepoints.
  */
-#define DEFINE_TRACE_FN(name, reg, unreg)                               \
+#define DEFINE_TRACE_FN(name, reg, unreg, proto, args)                 \
        static const char __tpstrtab_##name[]                            \
        __attribute__((section("__tracepoints_strings"))) = #name;       \
        struct tracepoint __tracepoint_##name                            \
        __attribute__((section("__tracepoints"), used)) =                \
-               { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\
-       __TRACEPOINT_ENTRY(name);
+               { __tpstrtab_##name, STATIC_KEY_INIT_FALSE,             \
+                 &___dyn_func__tp_func_##name, reg, unreg, NULL };     \
+       __TRACEPOINT_ENTRY(name);                                       \
+       int __tracepoint_iter_##name(void *__data, proto)               \
+       {                                                               \
+               struct tracepoint_func *it_func_ptr;                    \
+               void *it_func;                                          \
+                                                                       \
+               it_func_ptr =                                           \
+                       rcu_dereference_raw((&__tracepoint_##name)->funcs); \
+               do {                                                    \
+                       it_func = (it_func_ptr)->func;                  \
+                       __data = (it_func_ptr)->data;                   \
+                       ((void(*)(void *, proto))(it_func))(__data, args); \
+               } while ((++it_func_ptr)->func);                        \
+               return 0;                                               \
+       }                                                               \
+       DEFINE_DYNAMIC_FUNCTION(tp_func_##name, __tracepoint_iter_##name, \
+                               PARAMS(void *__data, proto))
 
-#define DEFINE_TRACE(name)                                             \
-       DEFINE_TRACE_FN(name, NULL, NULL);
+#define DEFINE_TRACE(name, proto, args)                \
+       DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
 
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)                             \
-       EXPORT_SYMBOL_GPL(__tracepoint_##name)
+       EXPORT_SYMBOL_GPL(__tracepoint_##name);                         \
+       EXPORT_SYMBOL_GPL(___dyn_func__tp_func_##name);                 \
+       EXPORT_SYMBOL_GPL(dynfunc_tp_func_##name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)                                 \
-       EXPORT_SYMBOL(__tracepoint_##name)
+       EXPORT_SYMBOL(__tracepoint_##name);                             \
+       EXPORT_SYMBOL(___dyn_func__tp_func_##name);                     \
+       EXPORT_SYMBOL(dynfunc_tp_func_##name)
+
 
 #else /* !TRACEPOINTS_ENABLED */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
@@ -314,8 +337,8 @@ extern void syscall_unregfunc(void);
                return false;                                           \
        }
 
-#define DEFINE_TRACE_FN(name, reg, unreg)
-#define DEFINE_TRACE(name)
+#define DEFINE_TRACE_FN(name, reg, unreg, proto, args)
+#define DEFINE_TRACE(name, proto, args)
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index cb30c5532144..c19aea44efb2 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -25,7 +25,7 @@
 
 #undef TRACE_EVENT
 #define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_EVENT_CONDITION
 #define TRACE_EVENT_CONDITION(name, proto, args, cond, tstruct, assign, print) 
\
@@ -39,24 +39,24 @@
 #undef TRACE_EVENT_FN
 #define TRACE_EVENT_FN(name, proto, args, tstruct,             \
                assign, print, reg, unreg)                      \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_EVENT_FN_COND
 #define TRACE_EVENT_FN_COND(name, proto, args, cond, tstruct,          \
                assign, print, reg, unreg)                      \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_FN
 #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_CONDITION
 #define DEFINE_EVENT_CONDITION(template, name, proto, args, cond) \
@@ -64,7 +64,7 @@
 
 #undef DECLARE_TRACE
 #define DECLARE_TRACE(name, proto, args)       \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_INCLUDE
 #undef __TRACE_INCLUDE
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index bf2c06ef9afc..b141f25d4b3a 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -140,7 +140,7 @@ static void debug_print_probes(struct tracepoint_func 
*funcs)
 
 static struct tracepoint_func *
 func_add(struct tracepoint_func **funcs, struct tracepoint_func *tp_func,
-        int prio)
+        int prio, int *tot_probes)
 {
        struct tracepoint_func *old, *new;
        int nr_probes = 0;
@@ -183,11 +183,12 @@ func_add(struct tracepoint_func **funcs, struct 
tracepoint_func *tp_func,
        new[nr_probes + 1].func = NULL;
        *funcs = new;
        debug_print_probes(*funcs);
+       *tot_probes = nr_probes + 1;
        return old;
 }
 
 static void *func_remove(struct tracepoint_func **funcs,
-               struct tracepoint_func *tp_func)
+               struct tracepoint_func *tp_func, int *left)
 {
        int nr_probes = 0, nr_del = 0, i;
        struct tracepoint_func *old, *new;
@@ -241,6 +242,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
                               struct tracepoint_func *func, int prio)
 {
        struct tracepoint_func *old, *tp_funcs;
+       int probes = 0;
        int ret;
 
        if (tp->regfunc && !static_key_enabled(&tp->key)) {
@@ -251,7 +253,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
 
        tp_funcs = rcu_dereference_protected(tp->funcs,
                        lockdep_is_held(&tracepoints_mutex));
-       old = func_add(&tp_funcs, func, prio);
+       old = func_add(&tp_funcs, func, prio, &probes);
        if (IS_ERR(old)) {
                WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
                return PTR_ERR(old);
@@ -266,6 +268,15 @@ static int tracepoint_add_func(struct tracepoint *tp,
        rcu_assign_pointer(tp->funcs, tp_funcs);
        if (!static_key_enabled(&tp->key))
                static_key_slow_inc(&tp->key);
+
+       if (probes == 1) {
+//             printk("make direct call to %pS\n", tp_funcs->func);
+               assign_dynamic_function(tp->dynfunc, tp_funcs->func);
+       } else {
+//             printk("[%d] make call to iterator %pS\n", probes, 
tp->dynfunc->func);
+               assign_dynamic_function(tp->dynfunc, tp->dynfunc->func);
+       }
+
        release_probes(old);
        return 0;
 }
@@ -280,10 +291,11 @@ static int tracepoint_remove_func(struct tracepoint *tp,
                struct tracepoint_func *func)
 {
        struct tracepoint_func *old, *tp_funcs;
+       int probes_left = 0;
 
        tp_funcs = rcu_dereference_protected(tp->funcs,
                        lockdep_is_held(&tracepoints_mutex));
-       old = func_remove(&tp_funcs, func);
+       old = func_remove(&tp_funcs, func, &probes_left);
        if (IS_ERR(old)) {
                WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
                return PTR_ERR(old);
@@ -297,6 +309,15 @@ static int tracepoint_remove_func(struct tracepoint *tp,
                if (static_key_enabled(&tp->key))
                        static_key_slow_dec(&tp->key);
        }
+
+       if (probes_left == 1) {
+//             printk("make direct call to %pS\n", tp_funcs->func);
+               assign_dynamic_function(tp->dynfunc, tp_funcs->func);
+       } else {
+//             printk("[%d] make call to iterator %pS\n", probes_left, 
tp->dynfunc->func);
+               assign_dynamic_function(tp->dynfunc, tp->dynfunc->func);
+       }
+
        rcu_assign_pointer(tp->funcs, tp_funcs);
        release_probes(old);
        return 0;
-- 
2.19.0


Reply via email to