diff options
-rw-r--r-- | include/linux/ftrace_event.h | 9 | ||||
-rw-r--r-- | include/trace/ftrace.h | 39 | ||||
-rw-r--r-- | kernel/trace/trace_event_profile.c | 41 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 50 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 44 |
5 files changed, 133 insertions, 50 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index f7b47c336703..43360c1d8f70 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -137,8 +137,13 @@ struct ftrace_event_call { | |||
137 | 137 | ||
138 | #define FTRACE_MAX_PROFILE_SIZE 2048 | 138 | #define FTRACE_MAX_PROFILE_SIZE 2048 |
139 | 139 | ||
140 | extern char *trace_profile_buf; | 140 | struct perf_trace_buf { |
141 | extern char *trace_profile_buf_nmi; | 141 | char buf[FTRACE_MAX_PROFILE_SIZE]; |
142 | int recursion; | ||
143 | }; | ||
144 | |||
145 | extern struct perf_trace_buf *perf_trace_buf; | ||
146 | extern struct perf_trace_buf *perf_trace_buf_nmi; | ||
142 | 147 | ||
143 | #define MAX_FILTER_PRED 32 | 148 | #define MAX_FILTER_PRED 32 |
144 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ | 149 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index a7f946094128..4945d1c99864 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -649,6 +649,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
649 | * struct ftrace_event_call *event_call = &event_<call>; | 649 | * struct ftrace_event_call *event_call = &event_<call>; |
650 | * extern void perf_tp_event(int, u64, u64, void *, int); | 650 | * extern void perf_tp_event(int, u64, u64, void *, int); |
651 | * struct ftrace_raw_##call *entry; | 651 | * struct ftrace_raw_##call *entry; |
652 | * struct perf_trace_buf *trace_buf; | ||
652 | * u64 __addr = 0, __count = 1; | 653 | * u64 __addr = 0, __count = 1; |
653 | * unsigned long irq_flags; | 654 | * unsigned long irq_flags; |
654 | * struct trace_entry *ent; | 655 | * struct trace_entry *ent; |
@@ -673,14 +674,25 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
673 | * __cpu = smp_processor_id(); | 674 | * __cpu = smp_processor_id(); |
674 | * | 675 | * |
675 | * if (in_nmi()) | 676 | * if (in_nmi()) |
676 | * raw_data = rcu_dereference(trace_profile_buf_nmi); | 677 | * trace_buf = rcu_dereference(perf_trace_buf_nmi); |
677 | * else | 678 | * else |
678 | * raw_data = rcu_dereference(trace_profile_buf); | 679 | * trace_buf = rcu_dereference(perf_trace_buf); |
679 | * | 680 | * |
680 | * if (!raw_data) | 681 | * if (!trace_buf) |
681 | * goto end; | 682 | * goto end; |
682 | * | 683 | * |
683 | * raw_data = per_cpu_ptr(raw_data, __cpu); | 684 | * trace_buf = per_cpu_ptr(trace_buf, __cpu); |
685 | * | ||
686 | * // Avoid recursion from perf that could mess up the buffer | ||
687 | * if (trace_buf->recursion++) | ||
688 | * goto end_recursion; | ||
689 | * | ||
690 | * raw_data = trace_buf->buf; | ||
691 | * | ||
692 | * // Make recursion update visible before entering perf_tp_event | ||
693 | * // so that we protect from perf recursions. | ||
694 | * | ||
695 | * barrier(); | ||
684 | * | 696 | * |
685 | * //zero dead bytes from alignment to avoid stack leak to userspace: | 697 | * //zero dead bytes from alignment to avoid stack leak to userspace: |
686 | * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; | 698 | * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; |
@@ -713,8 +725,9 @@ static void ftrace_profile_##call(proto) \ | |||
713 | { \ | 725 | { \ |
714 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ | 726 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ |
715 | struct ftrace_event_call *event_call = &event_##call; \ | 727 | struct ftrace_event_call *event_call = &event_##call; \ |
716 | extern void perf_tp_event(int, u64, u64, void *, int); \ | 728 | extern void perf_tp_event(int, u64, u64, void *, int); \ |
717 | struct ftrace_raw_##call *entry; \ | 729 | struct ftrace_raw_##call *entry; \ |
730 | struct perf_trace_buf *trace_buf; \ | ||
718 | u64 __addr = 0, __count = 1; \ | 731 | u64 __addr = 0, __count = 1; \ |
719 | unsigned long irq_flags; \ | 732 | unsigned long irq_flags; \ |
720 | struct trace_entry *ent; \ | 733 | struct trace_entry *ent; \ |
@@ -739,14 +752,20 @@ static void ftrace_profile_##call(proto) \ | |||
739 | __cpu = smp_processor_id(); \ | 752 | __cpu = smp_processor_id(); \ |
740 | \ | 753 | \ |
741 | if (in_nmi()) \ | 754 | if (in_nmi()) \ |
742 | raw_data = rcu_dereference(trace_profile_buf_nmi); \ | 755 | trace_buf = rcu_dereference(perf_trace_buf_nmi); \ |
743 | else \ | 756 | else \ |
744 | raw_data = rcu_dereference(trace_profile_buf); \ | 757 | trace_buf = rcu_dereference(perf_trace_buf); \ |
745 | \ | 758 | \ |
746 | if (!raw_data) \ | 759 | if (!trace_buf) \ |
747 | goto end; \ | 760 | goto end; \ |
748 | \ | 761 | \ |
749 | raw_data = per_cpu_ptr(raw_data, __cpu); \ | 762 | trace_buf = per_cpu_ptr(trace_buf, __cpu); \ |
763 | if (trace_buf->recursion++) \ | ||
764 | goto end_recursion; \ | ||
765 | \ | ||
766 | barrier(); \ | ||
767 | \ | ||
768 | raw_data = trace_buf->buf; \ | ||
750 | \ | 769 | \ |
751 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ | 770 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ |
752 | entry = (struct ftrace_raw_##call *)raw_data; \ | 771 | entry = (struct ftrace_raw_##call *)raw_data; \ |
@@ -761,6 +780,8 @@ static void ftrace_profile_##call(proto) \ | |||
761 | perf_tp_event(event_call->id, __addr, __count, entry, \ | 780 | perf_tp_event(event_call->id, __addr, __count, entry, \ |
762 | __entry_size); \ | 781 | __entry_size); \ |
763 | \ | 782 | \ |
783 | end_recursion: \ | ||
784 | trace_buf->recursion--; \ | ||
764 | end: \ | 785 | end: \ |
765 | local_irq_restore(irq_flags); \ | 786 | local_irq_restore(irq_flags); \ |
766 | \ | 787 | \ |
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index c9f687ab0d4f..e0d351b01f5a 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c | |||
@@ -8,41 +8,36 @@ | |||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include "trace.h" | 9 | #include "trace.h" |
10 | 10 | ||
11 | /* | ||
12 | * We can't use a size but a type in alloc_percpu() | ||
13 | * So let's create a dummy type that matches the desired size | ||
14 | */ | ||
15 | typedef struct {char buf[FTRACE_MAX_PROFILE_SIZE];} profile_buf_t; | ||
16 | 11 | ||
17 | char *trace_profile_buf; | 12 | struct perf_trace_buf *perf_trace_buf; |
18 | EXPORT_SYMBOL_GPL(trace_profile_buf); | 13 | EXPORT_SYMBOL_GPL(perf_trace_buf); |
19 | 14 | ||
20 | char *trace_profile_buf_nmi; | 15 | struct perf_trace_buf *perf_trace_buf_nmi; |
21 | EXPORT_SYMBOL_GPL(trace_profile_buf_nmi); | 16 | EXPORT_SYMBOL_GPL(perf_trace_buf_nmi); |
22 | 17 | ||
23 | /* Count the events in use (per event id, not per instance) */ | 18 | /* Count the events in use (per event id, not per instance) */ |
24 | static int total_profile_count; | 19 | static int total_profile_count; |
25 | 20 | ||
26 | static int ftrace_profile_enable_event(struct ftrace_event_call *event) | 21 | static int ftrace_profile_enable_event(struct ftrace_event_call *event) |
27 | { | 22 | { |
28 | char *buf; | 23 | struct perf_trace_buf *buf; |
29 | int ret = -ENOMEM; | 24 | int ret = -ENOMEM; |
30 | 25 | ||
31 | if (atomic_inc_return(&event->profile_count)) | 26 | if (atomic_inc_return(&event->profile_count)) |
32 | return 0; | 27 | return 0; |
33 | 28 | ||
34 | if (!total_profile_count) { | 29 | if (!total_profile_count) { |
35 | buf = (char *)alloc_percpu(profile_buf_t); | 30 | buf = alloc_percpu(struct perf_trace_buf); |
36 | if (!buf) | 31 | if (!buf) |
37 | goto fail_buf; | 32 | goto fail_buf; |
38 | 33 | ||
39 | rcu_assign_pointer(trace_profile_buf, buf); | 34 | rcu_assign_pointer(perf_trace_buf, buf); |
40 | 35 | ||
41 | buf = (char *)alloc_percpu(profile_buf_t); | 36 | buf = alloc_percpu(struct perf_trace_buf); |
42 | if (!buf) | 37 | if (!buf) |
43 | goto fail_buf_nmi; | 38 | goto fail_buf_nmi; |
44 | 39 | ||
45 | rcu_assign_pointer(trace_profile_buf_nmi, buf); | 40 | rcu_assign_pointer(perf_trace_buf_nmi, buf); |
46 | } | 41 | } |
47 | 42 | ||
48 | ret = event->profile_enable(event); | 43 | ret = event->profile_enable(event); |
@@ -53,10 +48,10 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event) | |||
53 | 48 | ||
54 | fail_buf_nmi: | 49 | fail_buf_nmi: |
55 | if (!total_profile_count) { | 50 | if (!total_profile_count) { |
56 | free_percpu(trace_profile_buf_nmi); | 51 | free_percpu(perf_trace_buf_nmi); |
57 | free_percpu(trace_profile_buf); | 52 | free_percpu(perf_trace_buf); |
58 | trace_profile_buf_nmi = NULL; | 53 | perf_trace_buf_nmi = NULL; |
59 | trace_profile_buf = NULL; | 54 | perf_trace_buf = NULL; |
60 | } | 55 | } |
61 | fail_buf: | 56 | fail_buf: |
62 | atomic_dec(&event->profile_count); | 57 | atomic_dec(&event->profile_count); |
@@ -84,7 +79,7 @@ int ftrace_profile_enable(int event_id) | |||
84 | 79 | ||
85 | static void ftrace_profile_disable_event(struct ftrace_event_call *event) | 80 | static void ftrace_profile_disable_event(struct ftrace_event_call *event) |
86 | { | 81 | { |
87 | char *buf, *nmi_buf; | 82 | struct perf_trace_buf *buf, *nmi_buf; |
88 | 83 | ||
89 | if (!atomic_add_negative(-1, &event->profile_count)) | 84 | if (!atomic_add_negative(-1, &event->profile_count)) |
90 | return; | 85 | return; |
@@ -92,11 +87,11 @@ static void ftrace_profile_disable_event(struct ftrace_event_call *event) | |||
92 | event->profile_disable(event); | 87 | event->profile_disable(event); |
93 | 88 | ||
94 | if (!--total_profile_count) { | 89 | if (!--total_profile_count) { |
95 | buf = trace_profile_buf; | 90 | buf = perf_trace_buf; |
96 | rcu_assign_pointer(trace_profile_buf, NULL); | 91 | rcu_assign_pointer(perf_trace_buf, NULL); |
97 | 92 | ||
98 | nmi_buf = trace_profile_buf_nmi; | 93 | nmi_buf = perf_trace_buf_nmi; |
99 | rcu_assign_pointer(trace_profile_buf_nmi, NULL); | 94 | rcu_assign_pointer(perf_trace_buf_nmi, NULL); |
100 | 95 | ||
101 | /* | 96 | /* |
102 | * Ensure every events in profiling have finished before | 97 | * Ensure every events in profiling have finished before |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index cf17a6694f32..3696476f307d 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1208,6 +1208,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1208 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | 1208 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); |
1209 | struct ftrace_event_call *call = &tp->call; | 1209 | struct ftrace_event_call *call = &tp->call; |
1210 | struct kprobe_trace_entry *entry; | 1210 | struct kprobe_trace_entry *entry; |
1211 | struct perf_trace_buf *trace_buf; | ||
1211 | struct trace_entry *ent; | 1212 | struct trace_entry *ent; |
1212 | int size, __size, i, pc, __cpu; | 1213 | int size, __size, i, pc, __cpu; |
1213 | unsigned long irq_flags; | 1214 | unsigned long irq_flags; |
@@ -1229,14 +1230,26 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1229 | __cpu = smp_processor_id(); | 1230 | __cpu = smp_processor_id(); |
1230 | 1231 | ||
1231 | if (in_nmi()) | 1232 | if (in_nmi()) |
1232 | raw_data = rcu_dereference(trace_profile_buf_nmi); | 1233 | trace_buf = rcu_dereference(perf_trace_buf_nmi); |
1233 | else | 1234 | else |
1234 | raw_data = rcu_dereference(trace_profile_buf); | 1235 | trace_buf = rcu_dereference(perf_trace_buf); |
1235 | 1236 | ||
1236 | if (!raw_data) | 1237 | if (!trace_buf) |
1237 | goto end; | 1238 | goto end; |
1238 | 1239 | ||
1239 | raw_data = per_cpu_ptr(raw_data, __cpu); | 1240 | trace_buf = per_cpu_ptr(trace_buf, __cpu); |
1241 | |||
1242 | if (trace_buf->recursion++) | ||
1243 | goto end_recursion; | ||
1244 | |||
1245 | /* | ||
1246 | * Make recursion update visible before entering perf_tp_event | ||
1247 | * so that we protect from perf recursions. | ||
1248 | */ | ||
1249 | barrier(); | ||
1250 | |||
1251 | raw_data = trace_buf->buf; | ||
1252 | |||
1240 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | 1253 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ |
1241 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 1254 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
1242 | entry = (struct kprobe_trace_entry *)raw_data; | 1255 | entry = (struct kprobe_trace_entry *)raw_data; |
@@ -1249,8 +1262,12 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1249 | for (i = 0; i < tp->nr_args; i++) | 1262 | for (i = 0; i < tp->nr_args; i++) |
1250 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1263 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1251 | perf_tp_event(call->id, entry->ip, 1, entry, size); | 1264 | perf_tp_event(call->id, entry->ip, 1, entry, size); |
1265 | |||
1266 | end_recursion: | ||
1267 | trace_buf->recursion--; | ||
1252 | end: | 1268 | end: |
1253 | local_irq_restore(irq_flags); | 1269 | local_irq_restore(irq_flags); |
1270 | |||
1254 | return 0; | 1271 | return 0; |
1255 | } | 1272 | } |
1256 | 1273 | ||
@@ -1261,6 +1278,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1261 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | 1278 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); |
1262 | struct ftrace_event_call *call = &tp->call; | 1279 | struct ftrace_event_call *call = &tp->call; |
1263 | struct kretprobe_trace_entry *entry; | 1280 | struct kretprobe_trace_entry *entry; |
1281 | struct perf_trace_buf *trace_buf; | ||
1264 | struct trace_entry *ent; | 1282 | struct trace_entry *ent; |
1265 | int size, __size, i, pc, __cpu; | 1283 | int size, __size, i, pc, __cpu; |
1266 | unsigned long irq_flags; | 1284 | unsigned long irq_flags; |
@@ -1282,14 +1300,26 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1282 | __cpu = smp_processor_id(); | 1300 | __cpu = smp_processor_id(); |
1283 | 1301 | ||
1284 | if (in_nmi()) | 1302 | if (in_nmi()) |
1285 | raw_data = rcu_dereference(trace_profile_buf_nmi); | 1303 | trace_buf = rcu_dereference(perf_trace_buf_nmi); |
1286 | else | 1304 | else |
1287 | raw_data = rcu_dereference(trace_profile_buf); | 1305 | trace_buf = rcu_dereference(perf_trace_buf); |
1288 | 1306 | ||
1289 | if (!raw_data) | 1307 | if (!trace_buf) |
1290 | goto end; | 1308 | goto end; |
1291 | 1309 | ||
1292 | raw_data = per_cpu_ptr(raw_data, __cpu); | 1310 | trace_buf = per_cpu_ptr(trace_buf, __cpu); |
1311 | |||
1312 | if (trace_buf->recursion++) | ||
1313 | goto end_recursion; | ||
1314 | |||
1315 | /* | ||
1316 | * Make recursion update visible before entering perf_tp_event | ||
1317 | * so that we protect from perf recursions. | ||
1318 | */ | ||
1319 | barrier(); | ||
1320 | |||
1321 | raw_data = trace_buf->buf; | ||
1322 | |||
1293 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | 1323 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ |
1294 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 1324 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
1295 | entry = (struct kretprobe_trace_entry *)raw_data; | 1325 | entry = (struct kretprobe_trace_entry *)raw_data; |
@@ -1303,8 +1333,12 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1303 | for (i = 0; i < tp->nr_args; i++) | 1333 | for (i = 0; i < tp->nr_args; i++) |
1304 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1334 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1305 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); | 1335 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); |
1336 | |||
1337 | end_recursion: | ||
1338 | trace_buf->recursion--; | ||
1306 | end: | 1339 | end: |
1307 | local_irq_restore(irq_flags); | 1340 | local_irq_restore(irq_flags); |
1341 | |||
1308 | return 0; | 1342 | return 0; |
1309 | } | 1343 | } |
1310 | 1344 | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 58b8e5370767..51213b0aa81b 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -477,6 +477,7 @@ static int sys_prof_refcount_exit; | |||
477 | static void prof_syscall_enter(struct pt_regs *regs, long id) | 477 | static void prof_syscall_enter(struct pt_regs *regs, long id) |
478 | { | 478 | { |
479 | struct syscall_metadata *sys_data; | 479 | struct syscall_metadata *sys_data; |
480 | struct perf_trace_buf *trace_buf; | ||
480 | struct syscall_trace_enter *rec; | 481 | struct syscall_trace_enter *rec; |
481 | unsigned long flags; | 482 | unsigned long flags; |
482 | char *raw_data; | 483 | char *raw_data; |
@@ -507,14 +508,25 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
507 | cpu = smp_processor_id(); | 508 | cpu = smp_processor_id(); |
508 | 509 | ||
509 | if (in_nmi()) | 510 | if (in_nmi()) |
510 | raw_data = rcu_dereference(trace_profile_buf_nmi); | 511 | trace_buf = rcu_dereference(perf_trace_buf_nmi); |
511 | else | 512 | else |
512 | raw_data = rcu_dereference(trace_profile_buf); | 513 | trace_buf = rcu_dereference(perf_trace_buf); |
513 | 514 | ||
514 | if (!raw_data) | 515 | if (!trace_buf) |
515 | goto end; | 516 | goto end; |
516 | 517 | ||
517 | raw_data = per_cpu_ptr(raw_data, cpu); | 518 | trace_buf = per_cpu_ptr(trace_buf, cpu); |
519 | |||
520 | if (trace_buf->recursion++) | ||
521 | goto end_recursion; | ||
522 | |||
523 | /* | ||
524 | * Make recursion update visible before entering perf_tp_event | ||
525 | * so that we protect from perf recursions. | ||
526 | */ | ||
527 | barrier(); | ||
528 | |||
529 | raw_data = trace_buf->buf; | ||
518 | 530 | ||
519 | /* zero the dead bytes from align to not leak stack to user */ | 531 | /* zero the dead bytes from align to not leak stack to user */ |
520 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 532 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -527,6 +539,8 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
527 | (unsigned long *)&rec->args); | 539 | (unsigned long *)&rec->args); |
528 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); | 540 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); |
529 | 541 | ||
542 | end_recursion: | ||
543 | trace_buf->recursion--; | ||
530 | end: | 544 | end: |
531 | local_irq_restore(flags); | 545 | local_irq_restore(flags); |
532 | } | 546 | } |
@@ -574,6 +588,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
574 | { | 588 | { |
575 | struct syscall_metadata *sys_data; | 589 | struct syscall_metadata *sys_data; |
576 | struct syscall_trace_exit *rec; | 590 | struct syscall_trace_exit *rec; |
591 | struct perf_trace_buf *trace_buf; | ||
577 | unsigned long flags; | 592 | unsigned long flags; |
578 | int syscall_nr; | 593 | int syscall_nr; |
579 | char *raw_data; | 594 | char *raw_data; |
@@ -605,14 +620,25 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
605 | cpu = smp_processor_id(); | 620 | cpu = smp_processor_id(); |
606 | 621 | ||
607 | if (in_nmi()) | 622 | if (in_nmi()) |
608 | raw_data = rcu_dereference(trace_profile_buf_nmi); | 623 | trace_buf = rcu_dereference(perf_trace_buf_nmi); |
609 | else | 624 | else |
610 | raw_data = rcu_dereference(trace_profile_buf); | 625 | trace_buf = rcu_dereference(perf_trace_buf); |
611 | 626 | ||
612 | if (!raw_data) | 627 | if (!trace_buf) |
613 | goto end; | 628 | goto end; |
614 | 629 | ||
615 | raw_data = per_cpu_ptr(raw_data, cpu); | 630 | trace_buf = per_cpu_ptr(trace_buf, cpu); |
631 | |||
632 | if (trace_buf->recursion++) | ||
633 | goto end_recursion; | ||
634 | |||
635 | /* | ||
636 | * Make recursion update visible before entering perf_tp_event | ||
637 | * so that we protect from perf recursions. | ||
638 | */ | ||
639 | barrier(); | ||
640 | |||
641 | raw_data = trace_buf->buf; | ||
616 | 642 | ||
617 | /* zero the dead bytes from align to not leak stack to user */ | 643 | /* zero the dead bytes from align to not leak stack to user */ |
618 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 644 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -626,6 +652,8 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
626 | 652 | ||
627 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); | 653 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); |
628 | 654 | ||
655 | end_recursion: | ||
656 | trace_buf->recursion--; | ||
629 | end: | 657 | end: |
630 | local_irq_restore(flags); | 658 | local_irq_restore(flags); |
631 | } | 659 | } |