Add dynamic ftrace_event_call support to ftrace. Trace engines can adds new
ftrace_event_call to ftrace on the fly. Each operator functions of the call
takes a ftrace_event_call data structure as an argument, because these
functions may be shared among several ftrace_event_calls.

Signed-off-by: Masami Hiramatsu <mhira...@redhat.com>
Cc: Steven Rostedt <rost...@goodmis.org>
Cc: Ingo Molnar <mi...@elte.hu>
Cc: Tom Zanussi <tzanu...@gmail.com>
Cc: Frederic Weisbecker <fweis...@gmail.com>
---

 include/linux/ftrace_event.h |   13 +++++---
 include/trace/ftrace.h       |   22 +++++++------
 kernel/trace/trace_events.c  |   70 ++++++++++++++++++++++++++++++++----------
 kernel/trace/trace_export.c  |   27 ++++++++--------
 4 files changed, 85 insertions(+), 47 deletions(-)

diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 5c093ff..f7733b6 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -108,12 +108,13 @@ struct ftrace_event_call {
        struct dentry           *dir;
        struct trace_event      *event;
        int                     enabled;
-       int                     (*regfunc)(void);
-       void                    (*unregfunc)(void);
+       int                     (*regfunc)(struct ftrace_event_call *);
+       void                    (*unregfunc)(struct ftrace_event_call *);
        int                     id;
-       int                     (*raw_init)(void);
-       int                     (*show_format)(struct trace_seq *s);
-       int                     (*define_fields)(void);
+       int                     (*raw_init)(struct ftrace_event_call *);
+       int                     (*show_format)(struct ftrace_event_call *,
+                                              struct trace_seq *);
+       int                     (*define_fields)(struct ftrace_event_call *);
        struct list_head        fields;
        int                     filter_active;
        void                    *filter;
@@ -138,6 +139,8 @@ extern int filter_current_check_discard(struct 
ftrace_event_call *call,
 
 extern int trace_define_field(struct ftrace_event_call *call, char *type,
                              char *name, int offset, int size, int is_signed);
+extern int trace_add_event_call(struct ftrace_event_call *call);
+extern void trace_remove_event_call(struct ftrace_event_call *call);
 
 #define is_signed_type(type)   (((type)(-1)) < 0)
 
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 1867553..d696580 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -147,7 +147,8 @@
 #undef TRACE_EVENT
 #define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
 static int                                                             \
-ftrace_format_##call(struct trace_seq *s)                              \
+ftrace_format_##call(struct ftrace_event_call *event_call,             \
+                    struct trace_seq *s)                               \
 {                                                                      \
        struct ftrace_raw_##call field __attribute__((unused));         \
        int ret = 0;                                                    \
@@ -289,10 +290,9 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int 
flags)   \
 #undef TRACE_EVENT
 #define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
 int                                                                    \
-ftrace_define_fields_##call(void)                                      \
+ftrace_define_fields_##call(struct ftrace_event_call *event_call)      \
 {                                                                      \
        struct ftrace_raw_##call field;                                 \
-       struct ftrace_event_call *event_call = &event_##call;           \
        int ret;                                                        \
                                                                        \
        __common_field(int, type, 1);                                   \
@@ -355,7 +355,7 @@ static inline int ftrace_get_offsets_##call(                
                \
  *     event_trace_printk(_RET_IP_, "<call>: " <fmt>);
  * }
  *
- * static int ftrace_reg_event_<call>(void)
+ * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int ret;
  *
@@ -366,7 +366,7 @@ static inline int ftrace_get_offsets_##call(                
                \
  *     return ret;
  * }
  *
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     unregister_trace_<call>(ftrace_event_<call>);
  * }
@@ -399,7 +399,7 @@ static inline int ftrace_get_offsets_##call(                
                \
  *     trace_current_buffer_unlock_commit(event, irq_flags, pc);
  * }
  *
- * static int ftrace_raw_reg_event_<call>(void)
+ * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int ret;
  *
@@ -410,7 +410,7 @@ static inline int ftrace_get_offsets_##call(                
                \
  *     return ret;
  * }
  *
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
  * {
  *     unregister_trace_<call>(ftrace_raw_event_<call>);
  * }
@@ -419,7 +419,7 @@ static inline int ftrace_get_offsets_##call(                
                \
  *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
  * };
  *
- * static int ftrace_raw_init_event_<call>(void)
+ * static int ftrace_raw_init_event_<call>(struct ftrace_event_call *unused)
  * {
  *     int id;
  *
@@ -537,7 +537,7 @@ static void ftrace_raw_event_##call(proto)                  
        \
                trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \
 }                                                                      \
                                                                        \
-static int ftrace_raw_reg_event_##call(void)                           \
+static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        int ret;                                                        \
                                                                        \
@@ -548,7 +548,7 @@ static int ftrace_raw_reg_event_##call(void)                
                \
        return ret;                                                     \
 }                                                                      \
                                                                        \
-static void ftrace_raw_unreg_event_##call(void)                                
\
+static void ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        unregister_trace_##call(ftrace_raw_event_##call);               \
 }                                                                      \
@@ -557,7 +557,7 @@ static struct trace_event ftrace_event_type_##call = {      
                \
        .trace                  = ftrace_raw_output_##call,             \
 };                                                                     \
                                                                        \
-static int ftrace_raw_init_event_##call(void)                          \
+static int ftrace_raw_init_event_##call(struct ftrace_event_call *unused)\
 {                                                                      \
        int id;                                                         \
                                                                        \
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index aa08be6..bdcfa30 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -60,9 +60,7 @@ err:
 }
 EXPORT_SYMBOL_GPL(trace_define_field);
 
-#ifdef CONFIG_MODULES
-
-static void trace_destroy_fields(struct ftrace_event_call *call)
+void trace_destroy_fields(struct ftrace_event_call *call)
 {
        struct ftrace_event_field *field, *next;
 
@@ -74,8 +72,6 @@ static void trace_destroy_fields(struct ftrace_event_call 
*call)
        }
 }
 
-#endif /* CONFIG_MODULES */
-
 static void ftrace_event_enable_disable(struct ftrace_event_call *call,
                                        int enable)
 {
@@ -84,14 +80,14 @@ static void ftrace_event_enable_disable(struct 
ftrace_event_call *call,
                if (call->enabled) {
                        call->enabled = 0;
                        tracing_stop_cmdline_record();
-                       call->unregfunc();
+                       call->unregfunc(call);
                }
                break;
        case 1:
                if (!call->enabled) {
                        call->enabled = 1;
                        tracing_start_cmdline_record();
-                       call->regfunc();
+                       call->regfunc(call);
                }
                break;
        }
@@ -558,7 +554,7 @@ event_format_read(struct file *filp, char __user *ubuf, 
size_t cnt,
        trace_seq_printf(s, "format:\n");
        trace_write_header(s);
 
-       r = call->show_format(s);
+       r = call->show_format(call, s);
        if (!r) {
                /*
                 * ug!  The format output is bigger than a PAGE!!
@@ -905,7 +901,7 @@ event_create_dir(struct ftrace_event_call *call, struct 
dentry *d_events,
                d_events = event_subsystem_dir(call->system, d_events);
 
        if (call->raw_init) {
-               ret = call->raw_init();
+               ret = call->raw_init(call);
                if (ret < 0) {
                        pr_warning("Could not initialize trace point"
                                   " events/%s\n", call->name);
@@ -929,7 +925,7 @@ event_create_dir(struct ftrace_event_call *call, struct 
dentry *d_events,
                                          id);
 
        if (call->define_fields) {
-               ret = call->define_fields();
+               ret = call->define_fields(call);
                if (ret < 0) {
                        pr_warning("Could not initialize trace point"
                                   " events/%s\n", call->name);
@@ -949,6 +945,52 @@ event_create_dir(struct ftrace_event_call *call, struct 
dentry *d_events,
        return 0;
 }
 
+static int __trace_add_event_call(struct ftrace_event_call *call)
+{
+       struct dentry *d_events;
+
+       if (!call->name)
+               return -EINVAL;
+
+       d_events = event_trace_events_dir();
+       if (!d_events)
+               return -ENOENT;
+
+       list_add(&call->list, &ftrace_events);
+       return event_create_dir(call, d_events, &ftrace_event_id_fops,
+                               &ftrace_enable_fops, &ftrace_event_filter_fops,
+                               &ftrace_event_format_fops);
+}
+
+/* Add an additional event_call dynamically */
+int trace_add_event_call(struct ftrace_event_call *call)
+{
+       int ret;
+       mutex_lock(&event_mutex);
+       ret = __trace_add_event_call(call);
+       mutex_unlock(&event_mutex);
+       return ret;
+}
+
+static void __trace_remove_event_call(struct ftrace_event_call *call)
+{
+       ftrace_event_enable_disable(call, 0);
+       if (call->event)
+               __unregister_ftrace_event(call->event);
+       debugfs_remove_recursive(call->dir);
+       list_del(&call->list);
+       trace_destroy_fields(call);
+       destroy_preds(call);
+}
+
+/* Remove an event_call */
+void trace_remove_event_call(struct ftrace_event_call *call)
+{
+       mutex_lock(&event_mutex);
+       __trace_remove_event_call(call);
+       mutex_unlock(&event_mutex);
+}
+
 #define for_each_event(event, start, end)                      \
        for (event = start;                                     \
             (unsigned long)event < (unsigned long)end;         \
@@ -1054,13 +1096,7 @@ static void trace_module_remove_events(struct module 
*mod)
        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);
-                       debugfs_remove_recursive(call->dir);
-                       list_del(&call->list);
-                       trace_destroy_fields(call);
-                       destroy_preds(call);
+                       __trace_remove_event_call(call);
                }
        }
 
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index d06cf89..7cee79d 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -60,7 +60,7 @@ extern void __bad_type_size(void);
 #undef TRACE_EVENT_FORMAT
 #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
 static int                                                             \
-ftrace_format_##call(struct trace_seq *s)                              \
+ftrace_format_##call(struct ftrace_event_call *dummy, struct trace_seq *s)\
 {                                                                      \
        struct args field;                                              \
        int ret;                                                        \
@@ -76,7 +76,7 @@ ftrace_format_##call(struct trace_seq *s)                     
        \
 #define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct,   \
                                    tpfmt)                              \
 static int                                                             \
-ftrace_format_##call(struct trace_seq *s)                              \
+ftrace_format_##call(struct ftrace_event_call *dummy, struct trace_seq *s)\
 {                                                                      \
        struct args field;                                              \
        int ret;                                                        \
@@ -115,10 +115,16 @@ ftrace_format_##call(struct trace_seq *s)                 
        \
 #define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \
        cmd;
 
+static int ftrace_raw_init_event(struct ftrace_event_call *event_call)
+{
+       INIT_LIST_HEAD(&event_call->fields);
+       init_preds(event_call);
+       return 0;
+}
+
 #undef TRACE_EVENT_FORMAT
 #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
-int ftrace_define_fields_##call(void);                                 \
-static int ftrace_raw_init_event_##call(void);                         \
+int ftrace_define_fields_##call(struct ftrace_event_call *c);          \
                                                                        \
 struct ftrace_event_call __used                                                
\
 __attribute__((__aligned__(4)))                                                
\
@@ -126,16 +132,10 @@ __attribute__((section("_ftrace_events"))) event_##call = 
{               \
        .name                   = #call,                                \
        .id                     = proto,                                \
        .system                 = __stringify(TRACE_SYSTEM),            \
-       .raw_init               = ftrace_raw_init_event_##call,         \
+       .raw_init               = ftrace_raw_init_event,                \
        .show_format            = ftrace_format_##call,                 \
        .define_fields          = ftrace_define_fields_##call,          \
-};                                                                     \
-static int ftrace_raw_init_event_##call(void)                          \
-{                                                                      \
-       INIT_LIST_HEAD(&event_##call.fields);                           \
-       init_preds(&event_##call);                                      \
-       return 0;                                                       \
-}                                                                      \
+};
 
 #undef TRACE_EVENT_FORMAT_NOFILTER
 #define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct,   \
@@ -182,9 +182,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { 
        \
 #undef TRACE_EVENT_FORMAT
 #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt)     \
 int                                                                    \
-ftrace_define_fields_##call(void)                                      \
+ftrace_define_fields_##call(struct ftrace_event_call *event_call)      \
 {                                                                      \
-       struct ftrace_event_call *event_call = &event_##call;           \
        struct args field;                                              \
        int ret;                                                        \
                                                                        \


-- 
Masami Hiramatsu

Software Engineer
Hitachi Computer Products (America), Inc.
Software Solutions Division

e-mail: mhira...@redhat.com
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to