diff options
-rw-r--r-- | include/linux/ftrace_event.h | 8 | ||||
-rw-r--r-- | include/linux/perf_event.h | 2 | ||||
-rw-r--r-- | include/trace/ftrace.h | 3 | ||||
-rw-r--r-- | kernel/perf_event.c | 15 | ||||
-rw-r--r-- | kernel/trace/trace_event_perf.c | 11 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 4 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 6 |
7 files changed, 31 insertions, 18 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index c0f4b364c71..c8091001b94 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -132,6 +132,7 @@ struct ftrace_event_call { | |||
132 | void *data; | 132 | void *data; |
133 | 133 | ||
134 | int perf_refcount; | 134 | int perf_refcount; |
135 | void *perf_data; | ||
135 | int (*perf_event_enable)(struct ftrace_event_call *); | 136 | int (*perf_event_enable)(struct ftrace_event_call *); |
136 | void (*perf_event_disable)(struct ftrace_event_call *); | 137 | void (*perf_event_disable)(struct ftrace_event_call *); |
137 | }; | 138 | }; |
@@ -190,7 +191,7 @@ struct perf_event; | |||
190 | 191 | ||
191 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); | 192 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); |
192 | 193 | ||
193 | extern int perf_trace_enable(int event_id); | 194 | extern int perf_trace_enable(int event_id, void *data); |
194 | extern void perf_trace_disable(int event_id); | 195 | extern void perf_trace_disable(int event_id); |
195 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 196 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, |
196 | char *filter_str); | 197 | char *filter_str); |
@@ -201,11 +202,12 @@ perf_trace_buf_prepare(int size, unsigned short type, int *rctxp, | |||
201 | 202 | ||
202 | static inline void | 203 | static inline void |
203 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, | 204 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, |
204 | u64 count, unsigned long irq_flags, struct pt_regs *regs) | 205 | u64 count, unsigned long irq_flags, struct pt_regs *regs, |
206 | void *event) | ||
205 | { | 207 | { |
206 | struct trace_entry *entry = raw_data; | 208 | struct trace_entry *entry = raw_data; |
207 | 209 | ||
208 | perf_tp_event(entry->type, addr, count, raw_data, size, regs); | 210 | perf_tp_event(entry->type, addr, count, raw_data, size, regs, event); |
209 | perf_swevent_put_recursion_context(rctx); | 211 | perf_swevent_put_recursion_context(rctx); |
210 | local_irq_restore(irq_flags); | 212 | local_irq_restore(irq_flags); |
211 | } | 213 | } |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 3fd5c82e0e1..0b521fc8f5b 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -994,7 +994,7 @@ static inline bool perf_paranoid_kernel(void) | |||
994 | 994 | ||
995 | extern void perf_event_init(void); | 995 | extern void perf_event_init(void); |
996 | extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 996 | extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
997 | int entry_size, struct pt_regs *regs); | 997 | int entry_size, struct pt_regs *regs, void *event); |
998 | extern void perf_bp_event(struct perf_event *event, void *data); | 998 | extern void perf_bp_event(struct perf_event *event, void *data); |
999 | 999 | ||
1000 | #ifndef perf_misc_flags | 1000 | #ifndef perf_misc_flags |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 882c64832ff..0a29df09292 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -785,7 +785,8 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call, \ | |||
785 | { assign; } \ | 785 | { assign; } \ |
786 | \ | 786 | \ |
787 | perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ | 787 | perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ |
788 | __count, irq_flags, __regs); \ | 788 | __count, irq_flags, __regs, \ |
789 | event_call->perf_data); \ | ||
789 | } | 790 | } |
790 | 791 | ||
791 | #undef DEFINE_EVENT | 792 | #undef DEFINE_EVENT |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index a4fa381db3c..17ac47f4bce 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -4468,8 +4468,9 @@ static int swevent_hlist_get(struct perf_event *event) | |||
4468 | #ifdef CONFIG_EVENT_TRACING | 4468 | #ifdef CONFIG_EVENT_TRACING |
4469 | 4469 | ||
4470 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 4470 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
4471 | int entry_size, struct pt_regs *regs) | 4471 | int entry_size, struct pt_regs *regs, void *event) |
4472 | { | 4472 | { |
4473 | const int type = PERF_TYPE_TRACEPOINT; | ||
4473 | struct perf_sample_data data; | 4474 | struct perf_sample_data data; |
4474 | struct perf_raw_record raw = { | 4475 | struct perf_raw_record raw = { |
4475 | .size = entry_size, | 4476 | .size = entry_size, |
@@ -4479,9 +4480,13 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4479 | perf_sample_data_init(&data, addr); | 4480 | perf_sample_data_init(&data, addr); |
4480 | data.raw = &raw; | 4481 | data.raw = &raw; |
4481 | 4482 | ||
4482 | /* Trace events already protected against recursion */ | 4483 | if (!event) { |
4483 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | 4484 | do_perf_sw_event(type, event_id, count, 1, &data, regs); |
4484 | &data, regs); | 4485 | return; |
4486 | } | ||
4487 | |||
4488 | if (perf_swevent_match(event, type, event_id, &data, regs)) | ||
4489 | perf_swevent_add(event, count, 1, &data, regs); | ||
4485 | } | 4490 | } |
4486 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4491 | EXPORT_SYMBOL_GPL(perf_tp_event); |
4487 | 4492 | ||
@@ -4514,7 +4519,7 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event) | |||
4514 | !capable(CAP_SYS_ADMIN)) | 4519 | !capable(CAP_SYS_ADMIN)) |
4515 | return ERR_PTR(-EPERM); | 4520 | return ERR_PTR(-EPERM); |
4516 | 4521 | ||
4517 | if (perf_trace_enable(event->attr.config)) | 4522 | if (perf_trace_enable(event->attr.config, event)) |
4518 | return NULL; | 4523 | return NULL; |
4519 | 4524 | ||
4520 | event->destroy = tp_perf_event_destroy; | 4525 | event->destroy = tp_perf_event_destroy; |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 0565bb42566..89b780a7c52 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -27,13 +27,15 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) | |||
27 | /* Count the events in use (per event id, not per instance) */ | 27 | /* Count the events in use (per event id, not per instance) */ |
28 | static int total_ref_count; | 28 | static int total_ref_count; |
29 | 29 | ||
30 | static int perf_trace_event_enable(struct ftrace_event_call *event) | 30 | static int perf_trace_event_enable(struct ftrace_event_call *event, void *data) |
31 | { | 31 | { |
32 | char *buf; | 32 | char *buf; |
33 | int ret = -ENOMEM; | 33 | int ret = -ENOMEM; |
34 | 34 | ||
35 | if (event->perf_refcount++ > 0) | 35 | if (event->perf_refcount++ > 0) { |
36 | event->perf_data = NULL; | ||
36 | return 0; | 37 | return 0; |
38 | } | ||
37 | 39 | ||
38 | if (!total_ref_count) { | 40 | if (!total_ref_count) { |
39 | buf = (char *)alloc_percpu(perf_trace_t); | 41 | buf = (char *)alloc_percpu(perf_trace_t); |
@@ -51,6 +53,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event) | |||
51 | 53 | ||
52 | ret = event->perf_event_enable(event); | 54 | ret = event->perf_event_enable(event); |
53 | if (!ret) { | 55 | if (!ret) { |
56 | event->perf_data = data; | ||
54 | total_ref_count++; | 57 | total_ref_count++; |
55 | return 0; | 58 | return 0; |
56 | } | 59 | } |
@@ -68,7 +71,7 @@ fail_buf: | |||
68 | return ret; | 71 | return ret; |
69 | } | 72 | } |
70 | 73 | ||
71 | int perf_trace_enable(int event_id) | 74 | int perf_trace_enable(int event_id, void *data) |
72 | { | 75 | { |
73 | struct ftrace_event_call *event; | 76 | struct ftrace_event_call *event; |
74 | int ret = -EINVAL; | 77 | int ret = -EINVAL; |
@@ -77,7 +80,7 @@ int perf_trace_enable(int event_id) | |||
77 | list_for_each_entry(event, &ftrace_events, list) { | 80 | list_for_each_entry(event, &ftrace_events, list) { |
78 | if (event->id == event_id && event->perf_event_enable && | 81 | if (event->id == event_id && event->perf_event_enable && |
79 | try_module_get(event->mod)) { | 82 | try_module_get(event->mod)) { |
80 | ret = perf_trace_event_enable(event); | 83 | ret = perf_trace_event_enable(event, data); |
81 | break; | 84 | break; |
82 | } | 85 | } |
83 | } | 86 | } |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a7514326052..2d7bf4146be 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1362,7 +1362,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, | |||
1362 | for (i = 0; i < tp->nr_args; i++) | 1362 | for (i = 0; i < tp->nr_args; i++) |
1363 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); | 1363 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
1364 | 1364 | ||
1365 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs); | 1365 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs, call->perf_data); |
1366 | } | 1366 | } |
1367 | 1367 | ||
1368 | /* Kretprobe profile handler */ | 1368 | /* Kretprobe profile handler */ |
@@ -1395,7 +1395,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, | |||
1395 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); | 1395 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
1396 | 1396 | ||
1397 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, | 1397 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, |
1398 | irq_flags, regs); | 1398 | irq_flags, regs, call->perf_data); |
1399 | } | 1399 | } |
1400 | 1400 | ||
1401 | static int probe_perf_enable(struct ftrace_event_call *call) | 1401 | static int probe_perf_enable(struct ftrace_event_call *call) |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 4d6d711717f..9eff1a4b49b 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -468,7 +468,8 @@ static void perf_syscall_enter(struct pt_regs *regs, long id) | |||
468 | rec->nr = syscall_nr; | 468 | rec->nr = syscall_nr; |
469 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, | 469 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, |
470 | (unsigned long *)&rec->args); | 470 | (unsigned long *)&rec->args); |
471 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); | 471 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs, |
472 | sys_data->enter_event->perf_data); | ||
472 | } | 473 | } |
473 | 474 | ||
474 | int perf_sysenter_enable(struct ftrace_event_call *call) | 475 | int perf_sysenter_enable(struct ftrace_event_call *call) |
@@ -543,7 +544,8 @@ static void perf_syscall_exit(struct pt_regs *regs, long ret) | |||
543 | rec->nr = syscall_nr; | 544 | rec->nr = syscall_nr; |
544 | rec->ret = syscall_get_return_value(current, regs); | 545 | rec->ret = syscall_get_return_value(current, regs); |
545 | 546 | ||
546 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); | 547 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs, |
548 | sys_data->exit_event->perf_data); | ||
547 | } | 549 | } |
548 | 550 | ||
549 | int perf_sysexit_enable(struct ftrace_event_call *call) | 551 | int perf_sysexit_enable(struct ftrace_event_call *call) |