void                    *data;
 
        int                     perf_refcount;
+       void                    *perf_data;
        int                     (*perf_event_enable)(struct ftrace_event_call *);
        void                    (*perf_event_disable)(struct ftrace_event_call *);
 };
 
 DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
 
-extern int perf_trace_enable(int event_id);
+extern int perf_trace_enable(int event_id, void *data);
 extern void perf_trace_disable(int event_id);
 extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
                                     char *filter_str);
 
 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, unsigned long irq_flags, struct pt_regs *regs,
+                      void *event)
 {
        struct trace_entry *entry = raw_data;
 
-       perf_tp_event(entry->type, addr, count, raw_data, size, regs);
+       perf_tp_event(entry->type, addr, count, raw_data, size, regs, event);
        perf_swevent_put_recursion_context(rctx);
        local_irq_restore(irq_flags);
 }
 
 
 extern void perf_event_init(void);
 extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
-                         int entry_size, struct pt_regs *regs);
+                         int entry_size, struct pt_regs *regs, void *event);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
 
        { assign; }                                                     \
                                                                        \
        perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
-                              __count, irq_flags, __regs);             \
+                              __count, irq_flags, __regs,              \
+                             event_call->perf_data);                   \
 }
 
 #undef DEFINE_EVENT
 
 #ifdef CONFIG_EVENT_TRACING
 
 void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
-                  int entry_size, struct pt_regs *regs)
+                  int entry_size, struct pt_regs *regs, void *event)
 {
+       const int type = PERF_TYPE_TRACEPOINT;
        struct perf_sample_data data;
        struct perf_raw_record raw = {
                .size = entry_size,
        perf_sample_data_init(&data, addr);
        data.raw = &raw;
 
-       /* Trace events already protected against recursion */
-       do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
-                        &data, regs);
+       if (!event) {
+               do_perf_sw_event(type, event_id, count, 1, &data, regs);
+               return;
+       }
+
+       if (perf_swevent_match(event, type, event_id, &data, regs))
+               perf_swevent_add(event, count, 1, &data, regs);
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
 
                        !capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
 
-       if (perf_trace_enable(event->attr.config))
+       if (perf_trace_enable(event->attr.config, event))
                return NULL;
 
        event->destroy = tp_perf_event_destroy;
 
 /* 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_enable(struct ftrace_event_call *event, void *data)
 {
        char *buf;
        int ret = -ENOMEM;
 
-       if (event->perf_refcount++ > 0)
+       if (event->perf_refcount++ > 0) {
+               event->perf_data = NULL;
                return 0;
+       }
 
        if (!total_ref_count) {
                buf = (char *)alloc_percpu(perf_trace_t);
 
        ret = event->perf_event_enable(event);
        if (!ret) {
+               event->perf_data = data;
                total_ref_count++;
                return 0;
        }
        return ret;
 }
 
-int perf_trace_enable(int event_id)
+int perf_trace_enable(int event_id, void *data)
 {
        struct ftrace_event_call *event;
        int ret = -EINVAL;
        list_for_each_entry(event, &ftrace_events, list) {
                if (event->id == event_id && event->perf_event_enable &&
                    try_module_get(event->mod)) {
-                       ret = perf_trace_event_enable(event);
+                       ret = perf_trace_event_enable(event, data);
                        break;
                }
        }
 
        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);
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs, call->perf_data);
 }
 
 /* Kretprobe profile handler */
                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);
+                              irq_flags, regs, call->perf_data);
 }
 
 static int probe_perf_enable(struct ftrace_event_call *call)
 
        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);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs,
+                       sys_data->enter_event->perf_data);
 }
 
 int perf_sysenter_enable(struct ftrace_event_call *call)
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
 
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs,
+                       sys_data->exit_event->perf_data);
 }
 
 int perf_sysexit_enable(struct ftrace_event_call *call)