This patch makes the field descriptions defined for event tracing
available at run-time, for the event-filtering mechanism introduced
in a subsequent patch.
The common event fields are prepended with 'common_' in the format
display, allowing them to be distinguished from the other fields
that might internally have same name and can therefore be
unambiguously used in filters.
Signed-off-by: Tom Zanussi <tzanussi@gmail.com>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <
1237710639.7703.46.camel@charm-linux>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
        TRACE_EVENT_TYPE_RAW            = 2,
 };
 
+struct ftrace_event_field {
+       struct list_head        link;
+       char                    *name;
+       char                    *type;
+       int                     offset;
+       int                     size;
+};
+
 struct ftrace_event_call {
-       char            *name;
-       char            *system;
-       struct dentry   *dir;
-       int             enabled;
-       int             (*regfunc)(void);
-       void            (*unregfunc)(void);
-       int             id;
-       int             (*raw_init)(void);
-       int             (*show_format)(struct trace_seq *s);
+       char                    *name;
+       char                    *system;
+       struct dentry           *dir;
+       int                     enabled;
+       int                     (*regfunc)(void);
+       void                    (*unregfunc)(void);
+       int                     id;
+       int                     (*raw_init)(void);
+       int                     (*show_format)(struct trace_seq *s);
+       int                     (*define_fields)(void);
+       struct list_head        fields;
 
 #ifdef CONFIG_EVENT_PROFILE
        atomic_t        profile_count;
 #endif
 };
 
+int trace_define_field(struct ftrace_event_call *call, char *type,
+                      char *name, int offset, int size);
 void event_trace_printk(unsigned long ip, const char *fmt, ...);
 extern struct ftrace_event_call __start_ftrace_events[];
 extern struct ftrace_event_call __stop_ftrace_events[];
 
 
 static DEFINE_MUTEX(event_mutex);
 
+int trace_define_field(struct ftrace_event_call *call, char *type,
+                      char *name, int offset, int size)
+{
+       struct ftrace_event_field *field;
+
+       field = kmalloc(sizeof(*field), GFP_KERNEL);
+       if (!field)
+               goto err;
+       field->name = kstrdup(name, GFP_KERNEL);
+       if (!field->name)
+               goto err;
+       field->type = kstrdup(type, GFP_KERNEL);
+       if (!field->type)
+               goto err;
+       field->offset = offset;
+       field->size = size;
+       list_add(&field->link, &call->fields);
+
+       return 0;
+err:
+       if (field) {
+               kfree(field->name);
+               kfree(field->type);
+       }
+       kfree(field);
+       return -ENOMEM;
+}
+
 static void ftrace_clear_events(void)
 {
        struct ftrace_event_call *call = (void *)__start_ftrace_events;
 
 #undef FIELD
 #define FIELD(type, name)                                              \
-       #type, #name, offsetof(typeof(field), name), sizeof(field.name)
+       #type, "common_" #name, offsetof(typeof(field), name),          \
+               sizeof(field.name)
 
 static int trace_write_header(struct trace_seq *s)
 {
                                        call->name);
        }
 
+       if (call->define_fields) {
+               ret = call->define_fields();
+               if (ret < 0) {
+                       pr_warning("Could not initialize trace point"
+                                  " events/%s\n", call->name);
+                       return ret;
+               }
+       }
+
        /* A trace may not want to export its format */
        if (!call->show_format)
                return 0;
 
 }
 
 #include <trace/trace_event_types.h>
+
+#undef __field
+#define __field(type, item)                                            \
+       ret = trace_define_field(event_call, #type, #item,              \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item));                   \
+       if (ret)                                                        \
+               return ret;
+
+#undef __array
+#define __array(type, item, len)                                       \
+       ret = trace_define_field(event_call, #type "[" #len "]", #item, \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item));                   \
+       if (ret)                                                        \
+               return ret;
+
+#define __common_field(type, item)                                     \
+       ret = trace_define_field(event_call, #type, "common_" #item,    \
+                                offsetof(typeof(field.ent), item),     \
+                                sizeof(field.ent.item));               \
+       if (ret)                                                        \
+               return ret;
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(call, proto, args, tstruct, func, print)           \
+int                                                                    \
+ftrace_define_fields_##call(void)                                      \
+{                                                                      \
+       struct ftrace_raw_##call field;                                 \
+       struct ftrace_event_call *event_call = &event_##call;           \
+       int ret;                                                        \
+                                                                       \
+       __common_field(unsigned char, type);                            \
+       __common_field(unsigned char, flags);                           \
+       __common_field(unsigned char, preempt_count);                   \
+       __common_field(int, pid);                                       \
+       __common_field(int, tgid);                                      \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return ret;                                                     \
+}
+
+#include <trace/trace_event_types.h>
 
        if (!id)                                                        \
                return -ENODEV;                                         \
        event_##call.id = id;                                           \
+       INIT_LIST_HEAD(&event_##call.fields);                           \
        return 0;                                                       \
 }                                                                      \
                                                                        \
        .regfunc                = ftrace_raw_reg_event_##call,          \
        .unregfunc              = ftrace_raw_unreg_event_##call,        \
        .show_format            = ftrace_format_##call,                 \
+       .define_fields          = ftrace_define_fields_##call,          \
        _TRACE_PROFILE_INIT(call)                                       \
 }