]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux...
authorSteven Rostedt <srostedt@redhat.com>
Fri, 21 May 2010 15:49:57 +0000 (11:49 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Fri, 21 May 2010 15:49:57 +0000 (11:49 -0400)
Conflicts:
include/linux/ftrace_event.h
include/trace/ftrace.h
kernel/trace/trace_event_perf.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_syscalls.c

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
1  2 
include/linux/ftrace_event.h
include/trace/ftrace.h
kernel/trace/trace_event_perf.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_syscalls.c

index dc7fc646fa2e7a9adfb1d2241f09ee3b11c47b81,7024b7d1126f1369d72453eab91fddb3b50c7a4e..ee8a8411b05503869c94ca0adbfa7f43414e6c4b
@@@ -70,25 -70,18 +70,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);
  
@@@ -120,67 -113,29 +120,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
@@@ -237,24 -192,22 +240,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
index e0e8daa6767e052d1a95b1bf1c95016de8049e85,4eb2148f13216b0d06c15b28891a76460812fbef..0152b8673bd7a35517980b5a040ae4b000182d91
                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                 \
   *
   *    entry = iter->ent;
   *
 - *    if (entry->type != event_<call>.id) {
 + *    if (entry->type != event_<call>->event.type) {
   *            WARN_ON_ONCE(1);
   *            return TRACE_TYPE_UNHANDLED;
   *    }
  #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)
  
@@@ -383,18 -378,80 +383,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)         \
 -{                                                                     \
 -      return register_trace_##call(ftrace_raw_event_##call);          \
 -}                                                                     \
 -                                                                      \
 -static notrace void                                                   \
 -ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)               \
 +static inline void ftrace_test_probe_##call(void)                     \
  {                                                                     \
 -      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)                     \
@@@ -574,10 -636,15 +574,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)                \
@@@ -588,9 -655,14 +588,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 = &get_cpu_var(perf_trace_regs);         \
++      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);                              \
++      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"))               \
-               goto out;                                               \
+               return;                                                 \
+                                                                       \
        entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
-               __entry_size, event_call->event.type, &rctx, &irq_flags); \
 -              __entry_size, event_call->id, __regs, &rctx);           \
++              __entry_size, event_call->event.type, &__regs, &rctx);  \
        if (!entry)                                                     \
-               goto out;                                               \
+               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);             \
-  out:                                                                 \
-       put_cpu_var(perf_trace_regs);                                   \
 -              __count, __regs, head);                                 \
++              __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;                                          \
 -                                                                      \
 -      perf_fetch_caller_regs(&__regs, 1);                             \
 -      perf_trace_templ_##template(event_call, &__regs, args);         \
 +      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))
index 0a47e8d6b4914e555ece3abec80a45db64f3c3d3,39d5ea7b0653540d2852a55349944824948e51f5..26b8607a0abc45205356d9b1d4a89afff16d3d04
@@@ -9,13 -9,9 +9,9 @@@
  #include <linux/kprobes.h>
  #include "trace.h"
  
- DEFINE_PER_CPU(struct pt_regs, perf_trace_regs);
- EXPORT_PER_CPU_SYMBOL_GPL(perf_trace_regs);
  EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
  
- static char *perf_trace_buf;
- static char *perf_trace_buf_nmi;
+ static char *perf_trace_buf[4];
  
  /*
   * Force it to be aligned to unsigned long to avoid misaligned accesses
@@@ -27,63 -23,75 +23,82 @@@ typedef typeof(unsigned long [PERF_MAX_
  /* Count the events in use (per event id, not per instance) */
  static int    total_ref_count;
  
- static int perf_trace_event_enable(struct ftrace_event_call *event)
+ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
+                                struct perf_event *p_event)
  {
-       char *buf;
+       struct hlist_head *list;
        int ret = -ENOMEM;
+       int cpu;
  
-       if (event->perf_refcount++ > 0)
+       p_event->tp_event = tp_event;
+       if (tp_event->perf_refcount++ > 0)
                return 0;
  
-       if (!total_ref_count) {
-               buf = (char *)alloc_percpu(perf_trace_t);
-               if (!buf)
-                       goto fail_buf;
+       list = alloc_percpu(struct hlist_head);
+       if (!list)
+               goto fail;
+       for_each_possible_cpu(cpu)
+               INIT_HLIST_HEAD(per_cpu_ptr(list, cpu));
  
-               rcu_assign_pointer(perf_trace_buf, buf);
+       tp_event->perf_events = list;
+       if (!total_ref_count) {
+               char *buf;
+               int i;
  
-               buf = (char *)alloc_percpu(perf_trace_t);
-               if (!buf)
-                       goto fail_buf_nmi;
+               for (i = 0; i < 4; i++) {
+                       buf = (char *)alloc_percpu(perf_trace_t);
+                       if (!buf)
+                               goto fail;
  
-               rcu_assign_pointer(perf_trace_buf_nmi, buf);
+                       perf_trace_buf[i] = buf;
+               }
        }
  
-       if (event->class->reg)
-               ret = event->class->reg(event, TRACE_REG_PERF_REGISTER);
 -      ret = tp_event->perf_event_enable(tp_event);
++      if (tp_event->class->reg)
++              ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
 +      else
-               ret = tracepoint_probe_register(event->name,
-                                               event->class->perf_probe,
-                                               event);
-       if (!ret) {
-               total_ref_count++;
-               return 0;
-       }
++              ret = tracepoint_probe_register(tp_event->name,
++                                              tp_event->class->perf_probe,
++                                              tp_event);
++
+       if (ret)
+               goto fail;
  
- fail_buf_nmi:
+       total_ref_count++;
+       return 0;
+ fail:
        if (!total_ref_count) {
-               free_percpu(perf_trace_buf_nmi);
-               free_percpu(perf_trace_buf);
-               perf_trace_buf_nmi = NULL;
-               perf_trace_buf = NULL;
+               int i;
+               for (i = 0; i < 4; i++) {
+                       free_percpu(perf_trace_buf[i]);
+                       perf_trace_buf[i] = NULL;
+               }
+       }
+       if (!--tp_event->perf_refcount) {
+               free_percpu(tp_event->perf_events);
+               tp_event->perf_events = NULL;
        }
- fail_buf:
-       event->perf_refcount--;
  
        return ret;
  }
  
- int perf_trace_enable(int event_id)
+ int perf_trace_init(struct perf_event *p_event)
  {
-       struct ftrace_event_call *event;
+       struct ftrace_event_call *tp_event;
+       int event_id = p_event->attr.config;
        int ret = -EINVAL;
  
        mutex_lock(&event_mutex);
-       list_for_each_entry(event, &ftrace_events, list) {
-               if (event->event.type == event_id &&
-                   event->class && event->class->perf_probe &&
-                   try_module_get(event->mod)) {
-                       ret = perf_trace_event_enable(event);
+       list_for_each_entry(tp_event, &ftrace_events, list) {
 -              if (tp_event->id == event_id && tp_event->perf_event_enable &&
++              if (tp_event->event.type == event_id &&
++                  tp_event->class && tp_event->class->perf_probe &&
+                   try_module_get(tp_event->mod)) {
+                       ret = perf_trace_event_init(tp_event, p_event);
                        break;
                }
        }
        return ret;
  }
  
static void perf_trace_event_disable(struct ftrace_event_call *event)
int perf_trace_enable(struct perf_event *p_event)
  {
-       char *buf, *nmi_buf;
-       if (--event->perf_refcount > 0)
-               return;
-       if (event->class->reg)
-               event->class->reg(event, TRACE_REG_PERF_UNREGISTER);
-       else
-               tracepoint_probe_unregister(event->name, event->class->perf_probe, event);
+       struct ftrace_event_call *tp_event = p_event->tp_event;
+       struct hlist_head *list;
  
-       if (!--total_ref_count) {
-               buf = perf_trace_buf;
-               rcu_assign_pointer(perf_trace_buf, NULL);
+       list = tp_event->perf_events;
+       if (WARN_ON_ONCE(!list))
+               return -EINVAL;
  
-               nmi_buf = perf_trace_buf_nmi;
-               rcu_assign_pointer(perf_trace_buf_nmi, NULL);
+       list = per_cpu_ptr(list, smp_processor_id());
+       hlist_add_head_rcu(&p_event->hlist_entry, list);
  
-               /*
-                * Ensure every events in profiling have finished before
-                * releasing the buffers
-                */
-               synchronize_sched();
+       return 0;
+ }
  
-               free_percpu(buf);
-               free_percpu(nmi_buf);
-       }
+ void perf_trace_disable(struct perf_event *p_event)
+ {
+       hlist_del_rcu(&p_event->hlist_entry);
  }
  
- void perf_trace_disable(int event_id)
+ void perf_trace_destroy(struct perf_event *p_event)
  {
-       struct ftrace_event_call *event;
+       struct ftrace_event_call *tp_event = p_event->tp_event;
+       int i;
  
-       mutex_lock(&event_mutex);
-       list_for_each_entry(event, &ftrace_events, list) {
-               if (event->event.type == event_id) {
-                       perf_trace_event_disable(event);
-                       module_put(event->mod);
-                       break;
+       if (--tp_event->perf_refcount > 0)
+               return;
 -      tp_event->perf_event_disable(tp_event);
++      if (tp_event->class->reg)
++              tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
++      else
++              tracepoint_probe_unregister(tp_event->name,
++                                          tp_event->class->perf_probe,
++                                          tp_event);
+       free_percpu(tp_event->perf_events);
+       tp_event->perf_events = NULL;
+       if (!--total_ref_count) {
+               for (i = 0; i < 4; i++) {
+                       free_percpu(perf_trace_buf[i]);
+                       perf_trace_buf[i] = NULL;
                }
        }
-       mutex_unlock(&event_mutex);
  }
  
  __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
-                                      int *rctxp, unsigned long *irq_flags)
+                                      struct pt_regs *regs, int *rctxp)
  {
        struct trace_entry *entry;
-       char *trace_buf, *raw_data;
-       int pc, cpu;
+       char *raw_data;
+       int pc;
  
        BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
  
        pc = preempt_count();
  
-       /* Protect the per cpu buffer, begin the rcu read side */
-       local_irq_save(*irq_flags);
        *rctxp = perf_swevent_get_recursion_context();
        if (*rctxp < 0)
-               goto err_recursion;
-       cpu = smp_processor_id();
-       if (in_nmi())
-               trace_buf = rcu_dereference_sched(perf_trace_buf_nmi);
-       else
-               trace_buf = rcu_dereference_sched(perf_trace_buf);
-       if (!trace_buf)
-               goto err;
+               return NULL;
  
-       raw_data = per_cpu_ptr(trace_buf, cpu);
+       raw_data = per_cpu_ptr(perf_trace_buf[*rctxp], smp_processor_id());
  
        /* zero the dead bytes from align to not leak stack to user */
        memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
  
        entry = (struct trace_entry *)raw_data;
-       tracing_generic_entry_update(entry, *irq_flags, pc);
+       tracing_generic_entry_update(entry, regs->flags, pc);
        entry->type = type;
  
        return raw_data;
- err:
-       perf_swevent_put_recursion_context(*rctxp);
- err_recursion:
-       local_irq_restore(*irq_flags);
-       return NULL;
  }
  EXPORT_SYMBOL_GPL(perf_trace_buf_prepare);
index 9a082bba95379d89c9aa04a140b6c0b0fd555fa8,4681f60dac00d020a0a28390151dcfd9e5fe4a81..faf7cefd15daf985afaadacb1d7a4b466993aa30
@@@ -324,8 -324,8 +324,8 @@@ struct trace_probe 
        unsigned long           nhit;
        unsigned int            flags;  /* For TP_FLAG_* */
        const char              *symbol;        /* symbol name */
 +      struct ftrace_event_class       class;
        struct ftrace_event_call        call;
 -      struct trace_event              event;
        ssize_t                 size;           /* trace entry size */
        unsigned int            nr_args;
        struct probe_arg        args[];
@@@ -404,7 -404,6 +404,7 @@@ static struct trace_probe *alloc_trace_
                goto error;
        }
  
 +      tp->call.class = &tp->class;
        tp->call.name = kstrdup(event, GFP_KERNEL);
        if (!tp->call.name)
                goto error;
                goto error;
        }
  
 -      tp->call.system = kstrdup(group, GFP_KERNEL);
 -      if (!tp->call.system)
 +      tp->class.system = kstrdup(group, GFP_KERNEL);
 +      if (!tp->class.system)
                goto error;
  
        INIT_LIST_HEAD(&tp->list);
@@@ -444,7 -443,7 +444,7 @@@ static void free_trace_probe(struct tra
        for (i = 0; i < tp->nr_args; i++)
                free_probe_arg(&tp->args[i]);
  
 -      kfree(tp->call.system);
 +      kfree(tp->call.class->system);
        kfree(tp->call.name);
        kfree(tp->symbol);
        kfree(tp);
@@@ -457,7 -456,7 +457,7 @@@ static struct trace_probe *find_probe_e
  
        list_for_each_entry(tp, &probe_list, list)
                if (strcmp(tp->call.name, event) == 0 &&
 -                  strcmp(tp->call.system, group) == 0)
 +                  strcmp(tp->call.class->system, group) == 0)
                        return tp;
        return NULL;
  }
@@@ -482,7 -481,7 +482,7 @@@ static int register_trace_probe(struct 
        mutex_lock(&probe_lock);
  
        /* register as an event */
 -      old_tp = find_probe_event(tp->call.name, tp->call.system);
 +      old_tp = find_probe_event(tp->call.name, tp->call.class->system);
        if (old_tp) {
                /* delete old event */
                unregister_trace_probe(old_tp);
@@@ -905,7 -904,7 +905,7 @@@ static int probes_seq_show(struct seq_f
        int i;
  
        seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p');
 -      seq_printf(m, ":%s/%s", tp->call.system, tp->call.name);
 +      seq_printf(m, ":%s/%s", tp->call.class->system, tp->call.name);
  
        if (!tp->symbol)
                seq_printf(m, " 0x%p", tp->rp.kp.addr);
@@@ -1062,8 -1061,8 +1062,8 @@@ static __kprobes void kprobe_trace_func
  
        size = sizeof(*entry) + tp->size;
  
 -      event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
 -                                                irq_flags, pc);
 +      event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
 +                                                size, irq_flags, pc);
        if (!event)
                return;
  
@@@ -1095,8 -1094,8 +1095,8 @@@ static __kprobes void kretprobe_trace_f
  
        size = sizeof(*entry) + tp->size;
  
 -      event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
 -                                                irq_flags, pc);
 +      event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
 +                                                size, irq_flags, pc);
        if (!event)
                return;
  
  
  /* Event entry printers */
  enum print_line_t
 -print_kprobe_event(struct trace_iterator *iter, int flags)
 +print_kprobe_event(struct trace_iterator *iter, int flags,
 +                 struct trace_event *event)
  {
        struct kprobe_trace_entry_head *field;
        struct trace_seq *s = &iter->seq;
 -      struct trace_event *event;
        struct trace_probe *tp;
        u8 *data;
        int i;
  
        field = (struct kprobe_trace_entry_head *)iter->ent;
 -      event = ftrace_find_event(field->ent.type);
 -      tp = container_of(event, struct trace_probe, event);
 +      tp = container_of(event, struct trace_probe, call.event);
  
        if (!trace_seq_printf(s, "%s: (", tp->call.name))
                goto partial;
@@@ -1149,17 -1149,18 +1149,17 @@@ partial
  }
  
  enum print_line_t
 -print_kretprobe_event(struct trace_iterator *iter, int flags)
 +print_kretprobe_event(struct trace_iterator *iter, int flags,
 +                    struct trace_event *event)
  {
        struct kretprobe_trace_entry_head *field;
        struct trace_seq *s = &iter->seq;
 -      struct trace_event *event;
        struct trace_probe *tp;
        u8 *data;
        int i;
  
        field = (struct kretprobe_trace_entry_head *)iter->ent;
 -      event = ftrace_find_event(field->ent.type);
 -      tp = container_of(event, struct trace_probe, event);
 +      tp = container_of(event, struct trace_probe, call.event);
  
        if (!trace_seq_printf(s, "%s: (", tp->call.name))
                goto partial;
@@@ -1216,6 -1217,8 +1216,6 @@@ static void probe_event_disable(struct 
  
  static int probe_event_raw_init(struct ftrace_event_call *event_call)
  {
 -      INIT_LIST_HEAD(&event_call->fields);
 -
        return 0;
  }
  
@@@ -1338,9 -1341,9 +1338,9 @@@ static __kprobes void kprobe_perf_func(
        struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
        struct ftrace_event_call *call = &tp->call;
        struct kprobe_trace_entry_head *entry;
+       struct hlist_head *head;
        u8 *data;
        int size, __size, i;
-       unsigned long irq_flags;
        int rctx;
  
        __size = sizeof(*entry) + tp->size;
                     "profile buffer not large enough"))
                return;
  
-       entry = perf_trace_buf_prepare(size, call->event.type,
-                                      &rctx, &irq_flags);
 -      entry = perf_trace_buf_prepare(size, call->id, regs, &rctx);
++      entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
                return;
  
        for (i = 0; i < tp->nr_args; i++)
                call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
  
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs);
+       head = per_cpu_ptr(call->perf_events, smp_processor_id());
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
  }
  
  /* Kretprobe profile handler */
@@@ -1370,9 -1373,9 +1370,9 @@@ static __kprobes void kretprobe_perf_fu
        struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
        struct ftrace_event_call *call = &tp->call;
        struct kretprobe_trace_entry_head *entry;
+       struct hlist_head *head;
        u8 *data;
        int size, __size, i;
-       unsigned long irq_flags;
        int rctx;
  
        __size = sizeof(*entry) + tp->size;
                     "profile buffer not large enough"))
                return;
  
-       entry = perf_trace_buf_prepare(size, call->event.type,
-                                      &rctx, &irq_flags);
 -      entry = perf_trace_buf_prepare(size, call->id, regs, &rctx);
++      entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
                return;
  
        for (i = 0; i < tp->nr_args; i++)
                call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
  
-       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1,
-                              irq_flags, regs);
+       head = per_cpu_ptr(call->perf_events, smp_processor_id());
+       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
  }
  
  static int probe_perf_enable(struct ftrace_event_call *call)
@@@ -1424,26 -1426,6 +1423,26 @@@ static void probe_perf_disable(struct f
  }
  #endif        /* CONFIG_PERF_EVENTS */
  
 +static __kprobes
 +int kprobe_register(struct ftrace_event_call *event, enum trace_reg type)
 +{
 +      switch (type) {
 +      case TRACE_REG_REGISTER:
 +              return probe_event_enable(event);
 +      case TRACE_REG_UNREGISTER:
 +              probe_event_disable(event);
 +              return 0;
 +
 +#ifdef CONFIG_PERF_EVENTS
 +      case TRACE_REG_PERF_REGISTER:
 +              return probe_perf_enable(event);
 +      case TRACE_REG_PERF_UNREGISTER:
 +              probe_perf_disable(event);
 +              return 0;
 +#endif
 +      }
 +      return 0;
 +}
  
  static __kprobes
  int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
@@@ -1473,14 -1455,6 +1472,14 @@@ int kretprobe_dispatcher(struct kretpro
        return 0;       /* We don't tweek kernel, so just return 0 */
  }
  
 +static struct trace_event_functions kretprobe_funcs = {
 +      .trace          = print_kretprobe_event
 +};
 +
 +static struct trace_event_functions kprobe_funcs = {
 +      .trace          = print_kprobe_event
 +};
 +
  static int register_probe_event(struct trace_probe *tp)
  {
        struct ftrace_event_call *call = &tp->call;
  
        /* Initialize ftrace_event_call */
        if (probe_is_return(tp)) {
 -              tp->event.trace = print_kretprobe_event;
 -              call->raw_init = probe_event_raw_init;
 -              call->define_fields = kretprobe_event_define_fields;
 +              INIT_LIST_HEAD(&call->class->fields);
 +              call->event.funcs = &kretprobe_funcs;
 +              call->class->raw_init = probe_event_raw_init;
 +              call->class->define_fields = kretprobe_event_define_fields;
        } else {
 -              tp->event.trace = print_kprobe_event;
 -              call->raw_init = probe_event_raw_init;
 -              call->define_fields = kprobe_event_define_fields;
 +              INIT_LIST_HEAD(&call->class->fields);
 +              call->event.funcs = &kprobe_funcs;
 +              call->class->raw_init = probe_event_raw_init;
 +              call->class->define_fields = kprobe_event_define_fields;
        }
        if (set_print_fmt(tp) < 0)
                return -ENOMEM;
 -      call->event = &tp->event;
 -      call->id = register_ftrace_event(&tp->event);
 -      if (!call->id) {
 +      ret = register_ftrace_event(&call->event);
 +      if (!ret) {
                kfree(call->print_fmt);
                return -ENODEV;
        }
 -      call->enabled = 0;
 -      call->regfunc = probe_event_enable;
 -      call->unregfunc = probe_event_disable;
 -
 -#ifdef CONFIG_PERF_EVENTS
 -      call->perf_event_enable = probe_perf_enable;
 -      call->perf_event_disable = probe_perf_disable;
 -#endif
 +      call->flags = 0;
 +      call->class->reg = kprobe_register;
        call->data = tp;
        ret = trace_add_event_call(call);
        if (ret) {
                pr_info("Failed to register kprobe event: %s\n", call->name);
                kfree(call->print_fmt);
 -              unregister_ftrace_event(&tp->event);
 +              unregister_ftrace_event(&call->event);
        }
        return ret;
  }
index 9d358301ae3eeea4503fc794a9127da87c94f3ad,eb769f2702913f933f9e5d1556cad24e5e44cd14..d2c859cec9ea85b6f2e32c4c016937bee450aacb
@@@ -15,54 -15,6 +15,54 @@@ static int sys_refcount_exit
  static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
  static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
  
 +static int syscall_enter_register(struct ftrace_event_call *event,
 +                               enum trace_reg type);
 +static int syscall_exit_register(struct ftrace_event_call *event,
 +                               enum trace_reg type);
 +
 +static int syscall_enter_define_fields(struct ftrace_event_call *call);
 +static int syscall_exit_define_fields(struct ftrace_event_call *call);
 +
 +static struct list_head *
 +syscall_get_enter_fields(struct ftrace_event_call *call)
 +{
 +      struct syscall_metadata *entry = call->data;
 +
 +      return &entry->enter_fields;
 +}
 +
 +static struct list_head *
 +syscall_get_exit_fields(struct ftrace_event_call *call)
 +{
 +      struct syscall_metadata *entry = call->data;
 +
 +      return &entry->exit_fields;
 +}
 +
 +struct trace_event_functions enter_syscall_print_funcs = {
 +      .trace                  = print_syscall_enter,
 +};
 +
 +struct trace_event_functions exit_syscall_print_funcs = {
 +      .trace                  = print_syscall_exit,
 +};
 +
 +struct ftrace_event_class event_class_syscall_enter = {
 +      .system                 = "syscalls",
 +      .reg                    = syscall_enter_register,
 +      .define_fields          = syscall_enter_define_fields,
 +      .get_fields             = syscall_get_enter_fields,
 +      .raw_init               = init_syscall_trace,
 +};
 +
 +struct ftrace_event_class event_class_syscall_exit = {
 +      .system                 = "syscalls",
 +      .reg                    = syscall_exit_register,
 +      .define_fields          = syscall_exit_define_fields,
 +      .get_fields             = syscall_get_exit_fields,
 +      .raw_init               = init_syscall_trace,
 +};
 +
  extern unsigned long __start_syscalls_metadata[];
  extern unsigned long __stop_syscalls_metadata[];
  
@@@ -101,8 -53,7 +101,8 @@@ static struct syscall_metadata *syscall
  }
  
  enum print_line_t
 -print_syscall_enter(struct trace_iterator *iter, int flags)
 +print_syscall_enter(struct trace_iterator *iter, int flags,
 +                  struct trace_event *event)
  {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
        if (!entry)
                goto end;
  
 -      if (entry->enter_event->id != ent->type) {
 +      if (entry->enter_event->event.type != ent->type) {
                WARN_ON_ONCE(1);
                goto end;
        }
@@@ -154,8 -105,7 +154,8 @@@ end
  }
  
  enum print_line_t
 -print_syscall_exit(struct trace_iterator *iter, int flags)
 +print_syscall_exit(struct trace_iterator *iter, int flags,
 +                 struct trace_event *event)
  {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
                return TRACE_TYPE_HANDLED;
        }
  
 -      if (entry->exit_event->id != ent->type) {
 +      if (entry->exit_event->event.type != ent->type) {
                WARN_ON_ONCE(1);
                return TRACE_TYPE_UNHANDLED;
        }
@@@ -255,7 -205,7 +255,7 @@@ static void free_syscall_print_fmt(stru
                kfree(call->print_fmt);
  }
  
 -int syscall_enter_define_fields(struct ftrace_event_call *call)
 +static int syscall_enter_define_fields(struct ftrace_event_call *call)
  {
        struct syscall_trace_enter trace;
        struct syscall_metadata *meta = call->data;
        return ret;
  }
  
 -int syscall_exit_define_fields(struct ftrace_event_call *call)
 +static int syscall_exit_define_fields(struct ftrace_event_call *call)
  {
        struct syscall_trace_exit trace;
        int ret;
        return ret;
  }
  
 -void ftrace_syscall_enter(struct pt_regs *regs, long id)
 +void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
  {
        struct syscall_trace_enter *entry;
        struct syscall_metadata *sys_data;
        size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
  
        event = trace_current_buffer_lock_reserve(&buffer,
 -                      sys_data->enter_event->id, size, 0, 0);
 +                      sys_data->enter_event->event.type, size, 0, 0);
        if (!event)
                return;
  
                trace_current_buffer_unlock_commit(buffer, event, 0, 0);
  }
  
 -void ftrace_syscall_exit(struct pt_regs *regs, long ret)
 +void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
  {
        struct syscall_trace_exit *entry;
        struct syscall_metadata *sys_data;
                return;
  
        event = trace_current_buffer_lock_reserve(&buffer,
 -                      sys_data->exit_event->id, sizeof(*entry), 0, 0);
 +                      sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
        if (!event)
                return;
  
@@@ -370,7 -320,7 +370,7 @@@ int reg_event_syscall_enter(struct ftra
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_enter)
 -              ret = register_trace_sys_enter(ftrace_syscall_enter);
 +              ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
        if (!ret) {
                set_bit(num, enabled_enter_syscalls);
                sys_refcount_enter++;
@@@ -390,7 -340,7 +390,7 @@@ void unreg_event_syscall_enter(struct f
        sys_refcount_enter--;
        clear_bit(num, enabled_enter_syscalls);
        if (!sys_refcount_enter)
 -              unregister_trace_sys_enter(ftrace_syscall_enter);
 +              unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
        mutex_unlock(&syscall_trace_lock);
  }
  
@@@ -404,7 -354,7 +404,7 @@@ int reg_event_syscall_exit(struct ftrac
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_exit)
 -              ret = register_trace_sys_exit(ftrace_syscall_exit);
 +              ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
        if (!ret) {
                set_bit(num, enabled_exit_syscalls);
                sys_refcount_exit++;
@@@ -424,7 -374,7 +424,7 @@@ void unreg_event_syscall_exit(struct ft
        sys_refcount_exit--;
        clear_bit(num, enabled_exit_syscalls);
        if (!sys_refcount_exit)
 -              unregister_trace_sys_exit(ftrace_syscall_exit);
 +              unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
        mutex_unlock(&syscall_trace_lock);
  }
  
@@@ -484,11 -434,11 +484,11 @@@ static DECLARE_BITMAP(enabled_perf_exit
  static int sys_perf_refcount_enter;
  static int sys_perf_refcount_exit;
  
 -static void perf_syscall_enter(struct pt_regs *regs, long id)
 +static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
  {
        struct syscall_metadata *sys_data;
        struct syscall_trace_enter *rec;
-       unsigned long flags;
+       struct hlist_head *head;
        int syscall_nr;
        int rctx;
        int size;
                return;
  
        rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
-                               sys_data->enter_event->event.type,
-                               &rctx, &flags);
 -                              sys_data->enter_event->id, regs, &rctx);
++                              sys_data->enter_event->event.type, regs, &rctx);
        if (!rec)
                return;
  
        rec->nr = syscall_nr;
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
+       head = per_cpu_ptr(sys_data->enter_event->perf_events, smp_processor_id());
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
  }
  
  int perf_sysenter_enable(struct ftrace_event_call *call)
  
        mutex_lock(&syscall_trace_lock);
        if (!sys_perf_refcount_enter)
 -              ret = register_trace_sys_enter(perf_syscall_enter);
 +              ret = register_trace_sys_enter(perf_syscall_enter, NULL);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall entry trace point");
@@@ -553,15 -504,15 +554,15 @@@ void perf_sysenter_disable(struct ftrac
        sys_perf_refcount_enter--;
        clear_bit(num, enabled_perf_enter_syscalls);
        if (!sys_perf_refcount_enter)
 -              unregister_trace_sys_enter(perf_syscall_enter);
 +              unregister_trace_sys_enter(perf_syscall_enter, NULL);
        mutex_unlock(&syscall_trace_lock);
  }
  
 -static void perf_syscall_exit(struct pt_regs *regs, long ret)
 +static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
  {
        struct syscall_metadata *sys_data;
        struct syscall_trace_exit *rec;
-       unsigned long flags;
+       struct hlist_head *head;
        int syscall_nr;
        int rctx;
        int size;
                return;
  
        rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
-                               sys_data->exit_event->event.type,
-                               &rctx, &flags);
 -                              sys_data->exit_event->id, regs, &rctx);
++                              sys_data->exit_event->event.type, regs, &rctx);
        if (!rec)
                return;
  
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
  
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
+       head = per_cpu_ptr(sys_data->exit_event->perf_events, smp_processor_id());
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
  }
  
  int perf_sysexit_enable(struct ftrace_event_call *call)
  
        mutex_lock(&syscall_trace_lock);
        if (!sys_perf_refcount_exit)
 -              ret = register_trace_sys_exit(perf_syscall_exit);
 +              ret = register_trace_sys_exit(perf_syscall_exit, NULL);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall exit trace point");
@@@ -629,50 -580,9 +630,50 @@@ void perf_sysexit_disable(struct ftrace
        sys_perf_refcount_exit--;
        clear_bit(num, enabled_perf_exit_syscalls);
        if (!sys_perf_refcount_exit)
 -              unregister_trace_sys_exit(perf_syscall_exit);
 +              unregister_trace_sys_exit(perf_syscall_exit, NULL);
        mutex_unlock(&syscall_trace_lock);
  }
  
  #endif /* CONFIG_PERF_EVENTS */
  
 +static int syscall_enter_register(struct ftrace_event_call *event,
 +                               enum trace_reg type)
 +{
 +      switch (type) {
 +      case TRACE_REG_REGISTER:
 +              return reg_event_syscall_enter(event);
 +      case TRACE_REG_UNREGISTER:
 +              unreg_event_syscall_enter(event);
 +              return 0;
 +
 +#ifdef CONFIG_PERF_EVENTS
 +      case TRACE_REG_PERF_REGISTER:
 +              return perf_sysenter_enable(event);
 +      case TRACE_REG_PERF_UNREGISTER:
 +              perf_sysenter_disable(event);
 +              return 0;
 +#endif
 +      }
 +      return 0;
 +}
 +
 +static int syscall_exit_register(struct ftrace_event_call *event,
 +                               enum trace_reg type)
 +{
 +      switch (type) {
 +      case TRACE_REG_REGISTER:
 +              return reg_event_syscall_exit(event);
 +      case TRACE_REG_UNREGISTER:
 +              unreg_event_syscall_exit(event);
 +              return 0;
 +
 +#ifdef CONFIG_PERF_EVENTS
 +      case TRACE_REG_PERF_REGISTER:
 +              return perf_sysexit_enable(event);
 +      case TRACE_REG_PERF_UNREGISTER:
 +              perf_sysexit_disable(event);
 +              return 0;
 +#endif
 +      }
 +      return 0;
 +}