Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 22:23:47 +0000 (15:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 22:23:47 +0000 (15:23 -0700)
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (61 commits)
  tracing: Add __used annotation to event variable
  perf, trace: Fix !x86 build bug
  perf report: Support multiple events on the TUI
  perf annotate: Fix up usage of the build id cache
  x86/mmiotrace: Remove redundant instruction prefix checks
  perf annotate: Add TUI interface
  perf tui: Remove annotate from popup menu after failure
  perf report: Don't start the TUI if -D is used
  perf: Fix getline undeclared
  perf: Optimize perf_tp_event_match()
  perf: Remove more code from the fastpath
  perf: Optimize the !vmalloc backed buffer
  perf: Optimize perf_output_copy()
  perf: Fix wakeup storm for RO mmap()s
  perf-record: Share per-cpu buffers
  perf-record: Remove -M
  perf: Ensure that IOC_OUTPUT isn't used to create multi-writer buffers
  perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events
  perf, trace: Optimize tracepoints by removing IRQ-disable from perf/tracepoint interaction
  perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig
  ...

1  2 
arch/sparc/kernel/perf_event.c
include/linux/ftrace_event.h
include/trace/ftrace.h
kernel/trace/trace.c
kernel/trace/trace_output.c

@@@ -14,7 -14,6 +14,7 @@@
  
  #include <linux/perf_event.h>
  #include <linux/kprobes.h>
 +#include <linux/ftrace.h>
  #include <linux/kernel.h>
  #include <linux/kdebug.h>
  #include <linux/mutex.h>
@@@ -92,6 -91,8 +92,8 @@@ struct cpu_hw_events 
  
        /* Enabled/disable state.  */
        int                     enabled;
+       unsigned int            group_flag;
  };
  DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };
  
@@@ -981,53 -982,6 +983,6 @@@ static int collect_events(struct perf_e
        return n;
  }
  
- static void event_sched_in(struct perf_event *event)
- {
-       event->state = PERF_EVENT_STATE_ACTIVE;
-       event->oncpu = smp_processor_id();
-       event->tstamp_running += event->ctx->time - event->tstamp_stopped;
-       if (is_software_event(event))
-               event->pmu->enable(event);
- }
- int hw_perf_group_sched_in(struct perf_event *group_leader,
-                          struct perf_cpu_context *cpuctx,
-                          struct perf_event_context *ctx)
- {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct perf_event *sub;
-       int n0, n;
-       if (!sparc_pmu)
-               return 0;
-       n0 = cpuc->n_events;
-       n = collect_events(group_leader, perf_max_events - n0,
-                          &cpuc->event[n0], &cpuc->events[n0],
-                          &cpuc->current_idx[n0]);
-       if (n < 0)
-               return -EAGAIN;
-       if (check_excludes(cpuc->event, n0, n))
-               return -EINVAL;
-       if (sparc_check_constraints(cpuc->event, cpuc->events, n + n0))
-               return -EAGAIN;
-       cpuc->n_events = n0 + n;
-       cpuc->n_added += n;
-       cpuctx->active_oncpu += n;
-       n = 1;
-       event_sched_in(group_leader);
-       list_for_each_entry(sub, &group_leader->sibling_list, group_entry) {
-               if (sub->state != PERF_EVENT_STATE_OFF) {
-                       event_sched_in(sub);
-                       n++;
-               }
-       }
-       ctx->nr_active += n;
-       return 1;
- }
  static int sparc_pmu_enable(struct perf_event *event)
  {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        cpuc->events[n0] = event->hw.event_base;
        cpuc->current_idx[n0] = PIC_NO_INDEX;
  
+       /*
+        * If group events scheduling transaction was started,
+        * skip the schedulability test here, it will be peformed
+        * at commit time(->commit_txn) as a whole
+        */
+       if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+               goto nocheck;
        if (check_excludes(cpuc->event, n0, 1))
                goto out;
        if (sparc_check_constraints(cpuc->event, cpuc->events, n0 + 1))
                goto out;
  
+ nocheck:
        cpuc->n_events++;
        cpuc->n_added++;
  
@@@ -1129,11 -1092,61 +1093,61 @@@ static int __hw_perf_event_init(struct 
        return 0;
  }
  
+ /*
+  * Start group events scheduling transaction
+  * Set the flag to make pmu::enable() not perform the
+  * schedulability test, it will be performed at commit time
+  */
+ static void sparc_pmu_start_txn(const struct pmu *pmu)
+ {
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       cpuhw->group_flag |= PERF_EVENT_TXN_STARTED;
+ }
+ /*
+  * Stop group events scheduling transaction
+  * Clear the flag and pmu::enable() will perform the
+  * schedulability test.
+  */
+ static void sparc_pmu_cancel_txn(const struct pmu *pmu)
+ {
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED;
+ }
+ /*
+  * Commit group events scheduling transaction
+  * Perform the group schedulability test as a whole
+  * Return 0 if success
+  */
+ static int sparc_pmu_commit_txn(const struct pmu *pmu)
+ {
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       int n;
+       if (!sparc_pmu)
+               return -EINVAL;
+       cpuc = &__get_cpu_var(cpu_hw_events);
+       n = cpuc->n_events;
+       if (check_excludes(cpuc->event, 0, n))
+               return -EINVAL;
+       if (sparc_check_constraints(cpuc->event, cpuc->events, n))
+               return -EAGAIN;
+       return 0;
+ }
  static const struct pmu pmu = {
        .enable         = sparc_pmu_enable,
        .disable        = sparc_pmu_disable,
        .read           = sparc_pmu_read,
        .unthrottle     = sparc_pmu_unthrottle,
+       .start_txn      = sparc_pmu_start_txn,
+       .cancel_txn     = sparc_pmu_cancel_txn,
+       .commit_txn     = sparc_pmu_commit_txn,
  };
  
  const struct pmu *hw_perf_event_init(struct perf_event *event)
@@@ -1277,9 -1290,6 +1291,9 @@@ static void perf_callchain_kernel(struc
                                  struct perf_callchain_entry *entry)
  {
        unsigned long ksp, fp;
 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 +      int graph = 0;
 +#endif
  
        callchain_store(entry, PERF_CONTEXT_KERNEL);
        callchain_store(entry, regs->tpc);
                        fp = (unsigned long)sf->fp + STACK_BIAS;
                }
                callchain_store(entry, pc);
 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 +              if ((pc + 8UL) == (unsigned long) &return_to_handler) {
 +                      int index = current->curr_ret_stack;
 +                      if (current->ret_stack && index >= graph) {
 +                              pc = current->ret_stack[index - graph].ret;
 +                              callchain_store(entry, pc);
 +                              graph++;
 +                      }
 +              }
 +#endif
        } while (entry->nr < PERF_MAX_STACK_DEPTH);
  }
  
@@@ -25,9 -25,6 +25,9 @@@ const char *ftrace_print_flags_seq(stru
  const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
                                     const struct trace_print_flags *symbol_array);
  
 +const char *ftrace_print_hex_seq(struct trace_seq *p,
 +                               const unsigned char *buf, int len);
 +
  /*
   * The trace entry - the most basic unit of tracing. This is what
   * is printed in the end as a single line in the trace output, such as:
@@@ -73,18 -70,25 +73,25 @@@ struct trace_iterator 
  };
  
  
+ struct trace_event;
  typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
-                                             int flags);
- struct trace_event {
-       struct hlist_node       node;
-       struct list_head        list;
-       int                     type;
+                                     int flags, struct trace_event *event);
+ struct trace_event_functions {
        trace_print_func        trace;
        trace_print_func        raw;
        trace_print_func        hex;
        trace_print_func        binary;
  };
  
+ struct trace_event {
+       struct hlist_node               node;
+       struct list_head                list;
+       int                             type;
+       struct trace_event_functions    *funcs;
+ };
  extern int register_ftrace_event(struct trace_event *event);
  extern int unregister_ftrace_event(struct trace_event *event);
  
@@@ -116,28 -120,70 +123,70 @@@ void tracing_record_cmdline(struct task
  
  struct event_filter;
  
+ enum trace_reg {
+       TRACE_REG_REGISTER,
+       TRACE_REG_UNREGISTER,
+       TRACE_REG_PERF_REGISTER,
+       TRACE_REG_PERF_UNREGISTER,
+ };
+ struct ftrace_event_call;
+ struct ftrace_event_class {
+       char                    *system;
+       void                    *probe;
+ #ifdef CONFIG_PERF_EVENTS
+       void                    *perf_probe;
+ #endif
+       int                     (*reg)(struct ftrace_event_call *event,
+                                      enum trace_reg type);
+       int                     (*define_fields)(struct ftrace_event_call *);
+       struct list_head        *(*get_fields)(struct ftrace_event_call *);
+       struct list_head        fields;
+       int                     (*raw_init)(struct ftrace_event_call *);
+ };
+ enum {
+       TRACE_EVENT_FL_ENABLED_BIT,
+       TRACE_EVENT_FL_FILTERED_BIT,
+ };
+ enum {
+       TRACE_EVENT_FL_ENABLED  = (1 << TRACE_EVENT_FL_ENABLED_BIT),
+       TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
+ };
  struct ftrace_event_call {
        struct list_head        list;
+       struct ftrace_event_class *class;
        char                    *name;
-       char                    *system;
        struct dentry           *dir;
-       struct trace_event      *event;
-       int                     enabled;
-       int                     (*regfunc)(struct ftrace_event_call *);
-       void                    (*unregfunc)(struct ftrace_event_call *);
-       int                     id;
+       struct trace_event      event;
        const char              *print_fmt;
-       int                     (*raw_init)(struct ftrace_event_call *);
-       int                     (*define_fields)(struct ftrace_event_call *);
-       struct list_head        fields;
-       int                     filter_active;
        struct event_filter     *filter;
        void                    *mod;
        void                    *data;
  
+       /*
+        * 32 bit flags:
+        *   bit 1:             enabled
+        *   bit 2:             filter_active
+        *
+        * Changes to flags must hold the event_mutex.
+        *
+        * Note: Reads of flags do not hold the event_mutex since
+        * they occur in critical sections. But the way flags
+        * is currently used, these changes do no affect the code
+        * except that when a change is made, it may have a slight
+        * delay in propagating the changes to other CPUs due to
+        * caching and such.
+        */
+       unsigned int            flags;
+ #ifdef CONFIG_PERF_EVENTS
        int                     perf_refcount;
-       int                     (*perf_event_enable)(struct ftrace_event_call *);
-       void                    (*perf_event_disable)(struct ftrace_event_call *);
+       struct hlist_head       *perf_events;
+ #endif
  };
  
  #define PERF_MAX_TRACE_SIZE   2048
@@@ -194,24 -240,22 +243,22 @@@ struct perf_event
  
  DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
  
- extern int perf_trace_enable(int event_id);
- extern void perf_trace_disable(int event_id);
- extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ extern int  perf_trace_init(struct perf_event *event);
+ extern void perf_trace_destroy(struct perf_event *event);
+ extern int  perf_trace_enable(struct perf_event *event);
+ extern void perf_trace_disable(struct perf_event *event);
+ extern int  ftrace_profile_set_filter(struct perf_event *event, int event_id,
                                     char *filter_str);
  extern void ftrace_profile_free_filter(struct perf_event *event);
- extern void *
- perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,
-                        unsigned long *irq_flags);
+ extern void *perf_trace_buf_prepare(int size, unsigned short type,
+                                   struct pt_regs *regs, int *rctxp);
  
  static inline void
  perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
-                      u64 count, unsigned long irq_flags, struct pt_regs *regs)
+                      u64 count, struct pt_regs *regs, void *head)
  {
-       struct trace_entry *entry = raw_data;
-       perf_tp_event(entry->type, addr, count, raw_data, size, regs);
+       perf_tp_event(addr, count, raw_data, size, regs, head);
        perf_swevent_put_recursion_context(rctx);
-       local_irq_restore(irq_flags);
  }
  #endif
  
diff --combined include/trace/ftrace.h
                struct trace_entry      ent;                            \
                tstruct                                                 \
                char                    __data[0];                      \
-       };
+       };                                                              \
+                                                                       \
+       static struct ftrace_event_class event_class_##name;
  #undef DEFINE_EVENT
  #define DEFINE_EVENT(template, name, proto, args)     \
-       static struct ftrace_event_call                 \
+       static struct ftrace_event_call __used          \
        __attribute__((__aligned__(4))) event_##name
  
  #undef DEFINE_EVENT_PRINT
   *
   *    entry = iter->ent;
   *
-  *    if (entry->type != event_<call>.id) {
+  *    if (entry->type != event_<call>->event.type) {
   *            WARN_ON_ONCE(1);
   *            return TRACE_TYPE_UNHANDLED;
   *    }
                ftrace_print_symbols_seq(p, value, symbols);            \
        })
  
 +#undef __print_hex
 +#define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len)
 +
  #undef DECLARE_EVENT_CLASS
  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)        \
  static notrace enum print_line_t                                      \
- ftrace_raw_output_id_##call(int event_id, const char *name,           \
-                           struct trace_iterator *iter, int flags)     \
+ ftrace_raw_output_##call(struct trace_iterator *iter, int flags,      \
+                        struct trace_event *trace_event)               \
  {                                                                     \
+       struct ftrace_event_call *event;                                \
        struct trace_seq *s = &iter->seq;                               \
        struct ftrace_raw_##call *field;                                \
        struct trace_entry *entry;                                      \
        struct trace_seq *p;                                            \
        int ret;                                                        \
                                                                        \
+       event = container_of(trace_event, struct ftrace_event_call,     \
+                            event);                                    \
+                                                                       \
        entry = iter->ent;                                              \
                                                                        \
-       if (entry->type != event_id) {                                  \
+       if (entry->type != event->event.type) {                         \
                WARN_ON_ONCE(1);                                        \
                return TRACE_TYPE_UNHANDLED;                            \
        }                                                               \
                                                                        \
        p = &get_cpu_var(ftrace_event_seq);                             \
        trace_seq_init(p);                                              \
-       ret = trace_seq_printf(s, "%s: ", name);                        \
+       ret = trace_seq_printf(s, "%s: ", event->name);                 \
        if (ret)                                                        \
                ret = trace_seq_printf(s, print);                       \
        put_cpu();                                                      \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
        return TRACE_TYPE_HANDLED;                                      \
- }
- #undef DEFINE_EVENT
- #define DEFINE_EVENT(template, name, proto, args)                     \
- static notrace enum print_line_t                                      \
- ftrace_raw_output_##name(struct trace_iterator *iter, int flags)      \
- {                                                                     \
-       return ftrace_raw_output_id_##template(event_##name.id,         \
-                                              #name, iter, flags);     \
- }
+ }                                                                     \
+ static struct trace_event_functions ftrace_event_type_funcs_##call = {        \
+       .trace                  = ftrace_raw_output_##call,             \
+ };
  
  #undef DEFINE_EVENT_PRINT
  #define DEFINE_EVENT_PRINT(template, call, proto, args, print)                \
  static notrace enum print_line_t                                      \
- ftrace_raw_output_##call(struct trace_iterator *iter, int flags)      \
+ ftrace_raw_output_##call(struct trace_iterator *iter, int flags,      \
+                        struct trace_event *event)                     \
  {                                                                     \
        struct trace_seq *s = &iter->seq;                               \
        struct ftrace_raw_##template *field;                            \
                                                                        \
        entry = iter->ent;                                              \
                                                                        \
-       if (entry->type != event_##call.id) {                           \
+       if (entry->type != event_##call.event.type) {                   \
                WARN_ON_ONCE(1);                                        \
                return TRACE_TYPE_UNHANDLED;                            \
        }                                                               \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
        return TRACE_TYPE_HANDLED;                                      \
- }
+ }                                                                     \
+ static struct trace_event_functions ftrace_event_type_funcs_##call = {        \
+       .trace                  = ftrace_raw_output_##call,             \
+ };
  
  #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
  
@@@ -381,80 -383,18 +386,18 @@@ static inline notrace int ftrace_get_of
  
  #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
  
- #ifdef CONFIG_PERF_EVENTS
- /*
-  * Generate the functions needed for tracepoint perf_event support.
-  *
-  * NOTE: The insertion profile callback (ftrace_profile_<call>) is defined later
-  *
-  * static int ftrace_profile_enable_<call>(void)
-  * {
-  *    return register_trace_<call>(ftrace_profile_<call>);
-  * }
-  *
-  * static void ftrace_profile_disable_<call>(void)
-  * {
-  *    unregister_trace_<call>(ftrace_profile_<call>);
-  * }
-  *
-  */
- #undef DECLARE_EVENT_CLASS
- #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)
- #undef DEFINE_EVENT
- #define DEFINE_EVENT(template, name, proto, args)                     \
-                                                                       \
- static void perf_trace_##name(proto);                                 \
-                                                                       \
- static notrace int                                                    \
- perf_trace_enable_##name(struct ftrace_event_call *unused)            \
- {                                                                     \
-       return register_trace_##name(perf_trace_##name);                \
- }                                                                     \
-                                                                       \
- static notrace void                                                   \
- perf_trace_disable_##name(struct ftrace_event_call *unused)           \
- {                                                                     \
-       unregister_trace_##name(perf_trace_##name);                     \
- }
- #undef DEFINE_EVENT_PRINT
- #define DEFINE_EVENT_PRINT(template, name, proto, args, print)        \
-       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
- #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
- #endif /* CONFIG_PERF_EVENTS */
  /*
   * Stage 4 of the trace events.
   *
   * Override the macros in <trace/trace_events.h> to include the following:
   *
-  * static void ftrace_event_<call>(proto)
-  * {
-  *    event_trace_printk(_RET_IP_, "<call>: " <fmt>);
-  * }
-  *
-  * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
-  * {
-  *    return register_trace_<call>(ftrace_event_<call>);
-  * }
-  *
-  * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
-  * {
-  *    unregister_trace_<call>(ftrace_event_<call>);
-  * }
-  *
-  *
   * For those macros defined with TRACE_EVENT:
   *
   * static struct ftrace_event_call event_<call>;
   *
-  * static void ftrace_raw_event_<call>(proto)
+  * static void ftrace_raw_event_<call>(void *__data, proto)
   * {
+  *    struct ftrace_event_call *event_call = __data;
   *    struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
   *    struct ring_buffer_event *event;
   *    struct ftrace_raw_<call> *entry; <-- defined in stage 1
   *    __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
   *
   *    event = trace_current_buffer_lock_reserve(&buffer,
-  *                              event_<call>.id,
+  *                              event_<call>->event.type,
   *                              sizeof(*entry) + __data_size,
   *                              irq_flags, pc);
   *    if (!event)
   *                                               event, irq_flags, pc);
   * }
   *
-  * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
-  * {
-  *    return register_trace_<call>(ftrace_raw_event_<call>);
-  * }
-  *
-  * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
-  * {
-  *    unregister_trace_<call>(ftrace_raw_event_<call>);
-  * }
-  *
   * static struct trace_event ftrace_event_type_<call> = {
   *    .trace                  = ftrace_raw_output_<call>, <-- stage 2
   * };
   *
   * static const char print_fmt_<call>[] = <TP_printk>;
   *
+  * static struct ftrace_event_class __used event_class_<template> = {
+  *    .system                 = "<system>",
+  *    .define_fields          = ftrace_define_fields_<call>,
+  *    .fields                 = LIST_HEAD_INIT(event_class_##call.fields),
+  *    .raw_init               = trace_event_raw_init,
+  *    .probe                  = ftrace_raw_event_##call,
+  * };
+  *
   * static struct ftrace_event_call __used
   * __attribute__((__aligned__(4)))
   * __attribute__((section("_ftrace_events"))) event_<call> = {
   *    .name                   = "<call>",
-  *    .system                 = "<system>",
-  *    .raw_init               = trace_event_raw_init,
-  *    .regfunc                = ftrace_reg_event_<call>,
-  *    .unregfunc              = ftrace_unreg_event_<call>,
+  *    .class                  = event_class_<template>,
+  *    .event                  = &ftrace_event_type_<call>,
   *    .print_fmt              = print_fmt_<call>,
-  *    .define_fields          = ftrace_define_fields_<call>,
-  * }
+  * };
   *
   */
  
  #ifdef CONFIG_PERF_EVENTS
  
+ #define _TRACE_PERF_PROTO(call, proto)                                        \
+       static notrace void                                             \
+       perf_trace_##call(void *__data, proto);
  #define _TRACE_PERF_INIT(call)                                                \
-       .perf_event_enable = perf_trace_enable_##call,                  \
-       .perf_event_disable = perf_trace_disable_##call,
+       .perf_probe             = perf_trace_##call,
  
  #else
+ #define _TRACE_PERF_PROTO(call, proto)
  #define _TRACE_PERF_INIT(call)
  #endif /* CONFIG_PERF_EVENTS */
  
  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)        \
                                                                        \
  static notrace void                                                   \
- ftrace_raw_event_id_##call(struct ftrace_event_call *event_call,      \
-                                      proto)                           \
+ ftrace_raw_event_##call(void *__data, proto)                          \
  {                                                                     \
+       struct ftrace_event_call *event_call = __data;                  \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ring_buffer_event *event;                                \
        struct ftrace_raw_##call *entry;                                \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
                                                                        \
        event = trace_current_buffer_lock_reserve(&buffer,              \
-                                event_call->id,                        \
+                                event_call->event.type,                \
                                 sizeof(*entry) + __data_size,          \
                                 irq_flags, pc);                        \
        if (!event)                                                     \
                trace_nowake_buffer_unlock_commit(buffer,               \
                                                  event, irq_flags, pc); \
  }
+ /*
+  * 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 notrace void ftrace_raw_event_##call(proto)                    \
- {                                                                     \
-       ftrace_raw_event_id_##template(&event_##call, args);            \
- }                                                                     \
-                                                                       \
- static notrace int                                                    \
- ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)         \
+ static inline void ftrace_test_probe_##call(void)                     \
  {                                                                     \
-       return register_trace_##call(ftrace_raw_event_##call);          \
- }                                                                     \
-                                                                       \
- static notrace void                                                   \
- ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)               \
- {                                                                     \
-       unregister_trace_##call(ftrace_raw_event_##call);               \
- }                                                                     \
-                                                                       \
- static struct trace_event ftrace_event_type_##call = {                        \
-       .trace                  = ftrace_raw_output_##call,             \
- };
+       check_trace_callback_type_##call(ftrace_raw_event_##template);  \
+ }
  
  #undef DEFINE_EVENT_PRINT
- #define DEFINE_EVENT_PRINT(template, name, proto, args, print)        \
-       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+ #define DEFINE_EVENT_PRINT(template, name, proto, args, print)
  
  #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
  
  
  #undef DECLARE_EVENT_CLASS
  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)        \
- static const char print_fmt_##call[] = print;
+ _TRACE_PERF_PROTO(call, PARAMS(proto));                                       \
+ static const char print_fmt_##call[] = print;                         \
+ static struct ftrace_event_class __used event_class_##call = {                \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .define_fields          = ftrace_define_fields_##call,          \
+       .fields                 = LIST_HEAD_INIT(event_class_##call.fields),\
+       .raw_init               = trace_event_raw_init,                 \
+       .probe                  = ftrace_raw_event_##call,              \
+       _TRACE_PERF_INIT(call)                                          \
+ };
  
  #undef DEFINE_EVENT
  #define DEFINE_EVENT(template, call, proto, args)                     \
@@@ -639,15 -574,10 +577,10 @@@ static struct ftrace_event_call __use
  __attribute__((__aligned__(4)))                                               \
  __attribute__((section("_ftrace_events"))) event_##call = {           \
        .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .event                  = &ftrace_event_type_##call,            \
-       .raw_init               = trace_event_raw_init,                 \
-       .regfunc                = ftrace_raw_reg_event_##call,          \
-       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##template,  \
        .print_fmt              = print_fmt_##template,                 \
-       .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PERF_INIT(call)                                  \
- }
+ };
  
  #undef DEFINE_EVENT_PRINT
  #define DEFINE_EVENT_PRINT(template, call, proto, args, print)                \
@@@ -658,14 -588,9 +591,9 @@@ static struct ftrace_event_call __use
  __attribute__((__aligned__(4)))                                               \
  __attribute__((section("_ftrace_events"))) event_##call = {           \
        .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .event                  = &ftrace_event_type_##call,            \
-       .raw_init               = trace_event_raw_init,                 \
-       .regfunc                = ftrace_raw_reg_event_##call,          \
-       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##call,      \
        .print_fmt              = print_fmt_##call,                     \
-       .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PERF_INIT(call)                                  \
  }
  
  #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
  #undef DECLARE_EVENT_CLASS
  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)        \
  static notrace void                                                   \
- perf_trace_templ_##call(struct ftrace_event_call *event_call,         \
-                       struct pt_regs *__regs, proto)                  \
+ perf_trace_##call(void *__data, proto)                                        \
  {                                                                     \
+       struct ftrace_event_call *event_call = __data;                  \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ftrace_raw_##call *entry;                                \
+       struct pt_regs __regs;                                          \
        u64 __addr = 0, __count = 1;                                    \
-       unsigned long irq_flags;                                        \
+       struct hlist_head *head;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
        int rctx;                                                       \
                                                                        \
+       perf_fetch_caller_regs(&__regs, 1);                             \
+                                                                       \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
        __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
                             sizeof(u64));                              \
        if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE,               \
                      "profile buffer not large enough"))               \
                return;                                                 \
+                                                                       \
        entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
-               __entry_size, event_call->id, &rctx, &irq_flags);       \
+               __entry_size, event_call->event.type, &__regs, &rctx);  \
        if (!entry)                                                     \
                return;                                                 \
+                                                                       \
        tstruct                                                         \
                                                                        \
        { assign; }                                                     \
                                                                        \
+       head = per_cpu_ptr(event_call->perf_events, smp_processor_id());\
        perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
-                              __count, irq_flags, __regs);             \
+               __count, &__regs, head);                                \
  }
  
+ /*
+  * 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 notrace void perf_trace_##call(proto)                          \
+ static inline void perf_test_probe_##call(void)                               \
  {                                                                     \
-       struct ftrace_event_call *event_call = &event_##call;           \
-       struct pt_regs *__regs = &get_cpu_var(perf_trace_regs);         \
-                                                                       \
-       perf_fetch_caller_regs(__regs, 1);                              \
-                                                                       \
-       perf_trace_templ_##template(event_call, __regs, args);          \
-                                                                       \
-       put_cpu_var(perf_trace_regs);                                   \
+       check_trace_callback_type_##call(perf_trace_##template);        \
  }
  
  #undef DEFINE_EVENT_PRINT
  #define DEFINE_EVENT_PRINT(template, name, proto, args, print)        \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
diff --combined kernel/trace/trace.c
@@@ -1936,7 -1936,7 +1936,7 @@@ static enum print_line_t print_trace_fm
        }
  
        if (event)
-               return event->trace(iter, sym_flags);
+               return event->funcs->trace(iter, sym_flags, event);
  
        if (!trace_seq_printf(s, "Unknown type %d\n", entry->type))
                goto partial;
@@@ -1962,7 -1962,7 +1962,7 @@@ static enum print_line_t print_raw_fmt(
  
        event = ftrace_find_event(entry->type);
        if (event)
-               return event->raw(iter, 0);
+               return event->funcs->raw(iter, 0, event);
  
        if (!trace_seq_printf(s, "%d ?\n", entry->type))
                goto partial;
@@@ -1989,7 -1989,7 +1989,7 @@@ static enum print_line_t print_hex_fmt(
  
        event = ftrace_find_event(entry->type);
        if (event) {
-               enum print_line_t ret = event->hex(iter, 0);
+               enum print_line_t ret = event->funcs->hex(iter, 0, event);
                if (ret != TRACE_TYPE_HANDLED)
                        return ret;
        }
@@@ -2014,7 -2014,8 +2014,8 @@@ static enum print_line_t print_bin_fmt(
        }
  
        event = ftrace_find_event(entry->type);
-       return event ? event->binary(iter, 0) : TRACE_TYPE_HANDLED;
+       return event ? event->funcs->binary(iter, 0, event) :
+               TRACE_TYPE_HANDLED;
  }
  
  int trace_empty(struct trace_iterator *iter)
@@@ -3309,12 -3310,12 +3310,12 @@@ static ssize_t tracing_splice_read_pipe
                                        size_t len,
                                        unsigned int flags)
  {
 -      struct page *pages[PIPE_BUFFERS];
 -      struct partial_page partial[PIPE_BUFFERS];
 +      struct page *pages_def[PIPE_DEF_BUFFERS];
 +      struct partial_page partial_def[PIPE_DEF_BUFFERS];
        struct trace_iterator *iter = filp->private_data;
        struct splice_pipe_desc spd = {
 -              .pages          = pages,
 -              .partial        = partial,
 +              .pages          = pages_def,
 +              .partial        = partial_def,
                .nr_pages       = 0, /* This gets updated below. */
                .flags          = flags,
                .ops            = &tracing_pipe_buf_ops,
        size_t rem;
        unsigned int i;
  
 +      if (splice_grow_spd(pipe, &spd))
 +              return -ENOMEM;
 +
        /* copy the tracer to avoid using a global lock all around */
        mutex_lock(&trace_types_lock);
        if (unlikely(old_tracer != current_trace && current_trace)) {
        trace_access_lock(iter->cpu_file);
  
        /* Fill as many pages as possible. */
 -      for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) {
 -              pages[i] = alloc_page(GFP_KERNEL);
 -              if (!pages[i])
 +      for (i = 0, rem = len; i < pipe->buffers && rem; i++) {
 +              spd.pages[i] = alloc_page(GFP_KERNEL);
 +              if (!spd.pages[i])
                        break;
  
                rem = tracing_fill_pipe_page(rem, iter);
  
                /* Copy the data into the page, so we can start over. */
                ret = trace_seq_to_buffer(&iter->seq,
 -                                        page_address(pages[i]),
 +                                        page_address(spd.pages[i]),
                                          iter->seq.len);
                if (ret < 0) {
 -                      __free_page(pages[i]);
 +                      __free_page(spd.pages[i]);
                        break;
                }
 -              partial[i].offset = 0;
 -              partial[i].len = iter->seq.len;
 +              spd.partial[i].offset = 0;
 +              spd.partial[i].len = iter->seq.len;
  
                trace_seq_init(&iter->seq);
        }
  
        spd.nr_pages = i;
  
 -      return splice_to_pipe(pipe, &spd);
 +      ret = splice_to_pipe(pipe, &spd);
 +out:
 +      splice_shrink_spd(pipe, &spd);
 +      return ret;
  
  out_err:
        mutex_unlock(&iter->mutex);
 -
 -      return ret;
 +      goto out;
  }
  
  static ssize_t
@@@ -3791,11 -3787,11 +3792,11 @@@ tracing_buffers_splice_read(struct fil
                            unsigned int flags)
  {
        struct ftrace_buffer_info *info = file->private_data;
 -      struct partial_page partial[PIPE_BUFFERS];
 -      struct page *pages[PIPE_BUFFERS];
 +      struct partial_page partial_def[PIPE_DEF_BUFFERS];
 +      struct page *pages_def[PIPE_DEF_BUFFERS];
        struct splice_pipe_desc spd = {
 -              .pages          = pages,
 -              .partial        = partial,
 +              .pages          = pages_def,
 +              .partial        = partial_def,
                .flags          = flags,
                .ops            = &buffer_pipe_buf_ops,
                .spd_release    = buffer_spd_release,
        int entries, size, i;
        size_t ret;
  
 +      if (splice_grow_spd(pipe, &spd))
 +              return -ENOMEM;
 +
        if (*ppos & (PAGE_SIZE - 1)) {
                WARN_ONCE(1, "Ftrace: previous read must page-align\n");
 -              return -EINVAL;
 +              ret = -EINVAL;
 +              goto out;
        }
  
        if (len & (PAGE_SIZE - 1)) {
                WARN_ONCE(1, "Ftrace: splice_read should page-align\n");
 -              if (len < PAGE_SIZE)
 -                      return -EINVAL;
 +              if (len < PAGE_SIZE) {
 +                      ret = -EINVAL;
 +                      goto out;
 +              }
                len &= PAGE_MASK;
        }
  
        trace_access_lock(info->cpu);
        entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
  
 -      for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) {
 +      for (i = 0; i < pipe->buffers && len && entries; i++, len -= PAGE_SIZE) {
                struct page *page;
                int r;
  
                else
                        ret = 0;
                /* TODO: block */
 -              return ret;
 +              goto out;
        }
  
        ret = splice_to_pipe(pipe, &spd);
 -
 +      splice_shrink_spd(pipe, &spd);
 +out:
        return ret;
  }
  
@@@ -209,7 -209,6 +209,7 @@@ int trace_seq_putc(struct trace_seq *s
  
        return 1;
  }
 +EXPORT_SYMBOL(trace_seq_putc);
  
  int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
  {
@@@ -356,21 -355,6 +356,21 @@@ ftrace_print_symbols_seq(struct trace_s
  }
  EXPORT_SYMBOL(ftrace_print_symbols_seq);
  
 +const char *
 +ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
 +{
 +      int i;
 +      const char *ret = p->buffer + p->len;
 +
 +      for (i = 0; i < buf_len; i++)
 +              trace_seq_printf(p, "%s%2.2x", i == 0 ? "" : " ", buf[i]);
 +
 +      trace_seq_putc(p, 0);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL(ftrace_print_hex_seq);
 +
  #ifdef CONFIG_KRETPROBES
  static inline const char *kretprobed(const char *name)
  {
@@@ -742,6 -726,9 +742,9 @@@ int register_ftrace_event(struct trace_
        if (WARN_ON(!event))
                goto out;
  
+       if (WARN_ON(!event->funcs))
+               goto out;
        INIT_LIST_HEAD(&event->list);
  
        if (!event->type) {
                        goto out;
        }
  
-       if (event->trace == NULL)
-               event->trace = trace_nop_print;
-       if (event->raw == NULL)
-               event->raw = trace_nop_print;
-       if (event->hex == NULL)
-               event->hex = trace_nop_print;
-       if (event->binary == NULL)
-               event->binary = trace_nop_print;
+       if (event->funcs->trace == NULL)
+               event->funcs->trace = trace_nop_print;
+       if (event->funcs->raw == NULL)
+               event->funcs->raw = trace_nop_print;
+       if (event->funcs->hex == NULL)
+               event->funcs->hex = trace_nop_print;
+       if (event->funcs->binary == NULL)
+               event->funcs->binary = trace_nop_print;
  
        key = event->type & (EVENT_HASHSIZE - 1);
  
@@@ -823,13 -810,15 +826,15 @@@ EXPORT_SYMBOL_GPL(unregister_ftrace_eve
   * Standard events
   */
  
- enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
+ enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags,
+                                 struct trace_event *event)
  {
        return TRACE_TYPE_HANDLED;
  }
  
  /* TRACE_FN */
- static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
  {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
- static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
  {
        struct ftrace_entry *field;
  
        return TRACE_TYPE_HANDLED;
  }
  
- static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
  {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_HANDLED;
  }
  
- static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
  {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_HANDLED;
  }
  
- static struct trace_event trace_fn_event = {
-       .type           = TRACE_FN,
+ static struct trace_event_functions trace_fn_funcs = {
        .trace          = trace_fn_trace,
        .raw            = trace_fn_raw,
        .hex            = trace_fn_hex,
        .binary         = trace_fn_bin,
  };
  
+ static struct trace_event trace_fn_event = {
+       .type           = TRACE_FN,
+       .funcs          = &trace_fn_funcs,
+ };
  /* TRACE_CTX an TRACE_WAKE */
  static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
                                             char *delim)
        return TRACE_TYPE_HANDLED;
  }
  
- static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags,
+                                        struct trace_event *event)
  {
        return trace_ctxwake_print(iter, "==>");
  }
  
  static enum print_line_t trace_wake_print(struct trace_iterator *iter,
-                                         int flags)
+                                         int flags, struct trace_event *event)
  {
        return trace_ctxwake_print(iter, "  +");
  }
@@@ -966,12 -963,14 +979,14 @@@ static int trace_ctxwake_raw(struct tra
        return TRACE_TYPE_HANDLED;
  }
  
- static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags,
+                                      struct trace_event *event)
  {
        return trace_ctxwake_raw(iter, 0);
  }
  
- static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
  {
        return trace_ctxwake_raw(iter, '+');
  }
@@@ -1000,18 -999,20 +1015,20 @@@ static int trace_ctxwake_hex(struct tra
        return TRACE_TYPE_HANDLED;
  }
  
- static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags,
+                                      struct trace_event *event)
  {
        return trace_ctxwake_hex(iter, 0);
  }
  
- static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
  {
        return trace_ctxwake_hex(iter, '+');
  }
  
  static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
  {
        struct ctx_switch_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_HANDLED;
  }
  
- static struct trace_event trace_ctx_event = {
-       .type           = TRACE_CTX,
+ static struct trace_event_functions trace_ctx_funcs = {
        .trace          = trace_ctx_print,
        .raw            = trace_ctx_raw,
        .hex            = trace_ctx_hex,
        .binary         = trace_ctxwake_bin,
  };
  
- static struct trace_event trace_wake_event = {
-       .type           = TRACE_WAKE,
+ static struct trace_event trace_ctx_event = {
+       .type           = TRACE_CTX,
+       .funcs          = &trace_ctx_funcs,
+ };
+ static struct trace_event_functions trace_wake_funcs = {
        .trace          = trace_wake_print,
        .raw            = trace_wake_raw,
        .hex            = trace_wake_hex,
        .binary         = trace_ctxwake_bin,
  };
  
+ static struct trace_event trace_wake_event = {
+       .type           = TRACE_WAKE,
+       .funcs          = &trace_wake_funcs,
+ };
  /* TRACE_SPECIAL */
  static enum print_line_t trace_special_print(struct trace_iterator *iter,
-                                            int flags)
+                                            int flags, struct trace_event *event)
  {
        struct special_entry *field;
  
  }
  
  static enum print_line_t trace_special_hex(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
  {
        struct special_entry *field;
        struct trace_seq *s = &iter->seq;
  }
  
  static enum print_line_t trace_special_bin(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
  {
        struct special_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_HANDLED;
  }
  
- static struct trace_event trace_special_event = {
-       .type           = TRACE_SPECIAL,
+ static struct trace_event_functions trace_special_funcs = {
        .trace          = trace_special_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
  };
  
+ static struct trace_event trace_special_event = {
+       .type           = TRACE_SPECIAL,
+       .funcs          = &trace_special_funcs,
+ };
  /* TRACE_STACK */
  
  static enum print_line_t trace_stack_print(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
  {
        struct stack_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
- static struct trace_event trace_stack_event = {
-       .type           = TRACE_STACK,
+ static struct trace_event_functions trace_stack_funcs = {
        .trace          = trace_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
  };
  
+ static struct trace_event trace_stack_event = {
+       .type           = TRACE_STACK,
+       .funcs          = &trace_stack_funcs,
+ };
  /* TRACE_USER_STACK */
  static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
-                                               int flags)
+                                               int flags, struct trace_event *event)
  {
        struct userstack_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
- static struct trace_event trace_user_stack_event = {
-       .type           = TRACE_USER_STACK,
+ static struct trace_event_functions trace_user_stack_funcs = {
        .trace          = trace_user_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
  };
  
+ static struct trace_event trace_user_stack_event = {
+       .type           = TRACE_USER_STACK,
+       .funcs          = &trace_user_stack_funcs,
+ };
  /* TRACE_BPRINT */
  static enum print_line_t
- trace_bprint_print(struct trace_iterator *iter, int flags)
+ trace_bprint_print(struct trace_iterator *iter, int flags,
+                  struct trace_event *event)
  {
        struct trace_entry *entry = iter->ent;
        struct trace_seq *s = &iter->seq;
  
  
  static enum print_line_t
- trace_bprint_raw(struct trace_iterator *iter, int flags)
+ trace_bprint_raw(struct trace_iterator *iter, int flags,
+                struct trace_event *event)
  {
        struct bprint_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
+ static struct trace_event_functions trace_bprint_funcs = {
+       .trace          = trace_bprint_print,
+       .raw            = trace_bprint_raw,
+ };
  
  static struct trace_event trace_bprint_event = {
        .type           = TRACE_BPRINT,
-       .trace          = trace_bprint_print,
-       .raw            = trace_bprint_raw,
+       .funcs          = &trace_bprint_funcs,
  };
  
  /* TRACE_PRINT */
  static enum print_line_t trace_print_print(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
  {
        struct print_entry *field;
        struct trace_seq *s = &iter->seq;
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
- static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
+ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags,
+                                        struct trace_event *event)
  {
        struct print_entry *field;
  
        return TRACE_TYPE_PARTIAL_LINE;
  }
  
- static struct trace_event trace_print_event = {
-       .type           = TRACE_PRINT,
+ static struct trace_event_functions trace_print_funcs = {
        .trace          = trace_print_print,
        .raw            = trace_print_raw,
  };
  
+ static struct trace_event trace_print_event = {
+       .type           = TRACE_PRINT,
+       .funcs          = &trace_print_funcs,
+ };
  
  static struct trace_event *events[] __initdata = {
        &trace_fn_event,