diff options
-rw-r--r-- | include/linux/ftrace_event.h | 9 | ||||
-rw-r--r-- | include/linux/perf_event.h | 4 | ||||
-rw-r--r-- | include/trace/ftrace.h | 23 | ||||
-rw-r--r-- | kernel/perf_event.c | 68 | ||||
-rw-r--r-- | kernel/trace/trace_event_profile.c | 14 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 48 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 47 |
7 files changed, 106 insertions, 107 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 43360c1d8f70..47bbdf9c38d0 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -137,13 +137,8 @@ struct ftrace_event_call { | |||
137 | 137 | ||
138 | #define FTRACE_MAX_PROFILE_SIZE 2048 | 138 | #define FTRACE_MAX_PROFILE_SIZE 2048 |
139 | 139 | ||
140 | struct perf_trace_buf { | 140 | extern char *perf_trace_buf; |
141 | char buf[FTRACE_MAX_PROFILE_SIZE]; | 141 | extern char *perf_trace_buf_nmi; |
142 | int recursion; | ||
143 | }; | ||
144 | |||
145 | extern struct perf_trace_buf *perf_trace_buf; | ||
146 | extern struct perf_trace_buf *perf_trace_buf_nmi; | ||
147 | 142 | ||
148 | #define MAX_FILTER_PRED 32 | 143 | #define MAX_FILTER_PRED 32 |
149 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ | 144 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 36fe89f72641..74e98b1d3391 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -874,6 +874,8 @@ extern int perf_output_begin(struct perf_output_handle *handle, | |||
874 | extern void perf_output_end(struct perf_output_handle *handle); | 874 | extern void perf_output_end(struct perf_output_handle *handle); |
875 | extern void perf_output_copy(struct perf_output_handle *handle, | 875 | extern void perf_output_copy(struct perf_output_handle *handle, |
876 | const void *buf, unsigned int len); | 876 | const void *buf, unsigned int len); |
877 | extern int perf_swevent_get_recursion_context(int **recursion); | ||
878 | extern void perf_swevent_put_recursion_context(int *recursion); | ||
877 | #else | 879 | #else |
878 | static inline void | 880 | static inline void |
879 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } | 881 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } |
@@ -902,6 +904,8 @@ static inline void perf_event_mmap(struct vm_area_struct *vma) { } | |||
902 | static inline void perf_event_comm(struct task_struct *tsk) { } | 904 | static inline void perf_event_comm(struct task_struct *tsk) { } |
903 | static inline void perf_event_fork(struct task_struct *tsk) { } | 905 | static inline void perf_event_fork(struct task_struct *tsk) { } |
904 | static inline void perf_event_init(void) { } | 906 | static inline void perf_event_init(void) { } |
907 | static int perf_swevent_get_recursion_context(int **recursion) { return -1; } | ||
908 | static void perf_swevent_put_recursion_context(int *recursion) { } | ||
905 | 909 | ||
906 | #endif | 910 | #endif |
907 | 911 | ||
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 4945d1c99864..c222ef5238bf 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -724,16 +724,19 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
724 | static void ftrace_profile_##call(proto) \ | 724 | static void ftrace_profile_##call(proto) \ |
725 | { \ | 725 | { \ |
726 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ | 726 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ |
727 | extern int perf_swevent_get_recursion_context(int **recursion); \ | ||
728 | extern void perf_swevent_put_recursion_context(int *recursion); \ | ||
727 | struct ftrace_event_call *event_call = &event_##call; \ | 729 | struct ftrace_event_call *event_call = &event_##call; \ |
728 | extern void perf_tp_event(int, u64, u64, void *, int); \ | 730 | extern void perf_tp_event(int, u64, u64, void *, int); \ |
729 | struct ftrace_raw_##call *entry; \ | 731 | struct ftrace_raw_##call *entry; \ |
730 | struct perf_trace_buf *trace_buf; \ | ||
731 | u64 __addr = 0, __count = 1; \ | 732 | u64 __addr = 0, __count = 1; \ |
732 | unsigned long irq_flags; \ | 733 | unsigned long irq_flags; \ |
733 | struct trace_entry *ent; \ | 734 | struct trace_entry *ent; \ |
734 | int __entry_size; \ | 735 | int __entry_size; \ |
735 | int __data_size; \ | 736 | int __data_size; \ |
737 | char *trace_buf; \ | ||
736 | char *raw_data; \ | 738 | char *raw_data; \ |
739 | int *recursion; \ | ||
737 | int __cpu; \ | 740 | int __cpu; \ |
738 | int pc; \ | 741 | int pc; \ |
739 | \ | 742 | \ |
@@ -749,6 +752,10 @@ static void ftrace_profile_##call(proto) \ | |||
749 | return; \ | 752 | return; \ |
750 | \ | 753 | \ |
751 | local_irq_save(irq_flags); \ | 754 | local_irq_save(irq_flags); \ |
755 | \ | ||
756 | if (perf_swevent_get_recursion_context(&recursion)) \ | ||
757 | goto end_recursion; \ | ||
758 | \ | ||
752 | __cpu = smp_processor_id(); \ | 759 | __cpu = smp_processor_id(); \ |
753 | \ | 760 | \ |
754 | if (in_nmi()) \ | 761 | if (in_nmi()) \ |
@@ -759,13 +766,7 @@ static void ftrace_profile_##call(proto) \ | |||
759 | if (!trace_buf) \ | 766 | if (!trace_buf) \ |
760 | goto end; \ | 767 | goto end; \ |
761 | \ | 768 | \ |
762 | trace_buf = per_cpu_ptr(trace_buf, __cpu); \ | 769 | raw_data = 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; \ | ||
769 | \ | 770 | \ |
770 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ | 771 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ |
771 | entry = (struct ftrace_raw_##call *)raw_data; \ | 772 | entry = (struct ftrace_raw_##call *)raw_data; \ |
@@ -780,9 +781,9 @@ static void ftrace_profile_##call(proto) \ | |||
780 | perf_tp_event(event_call->id, __addr, __count, entry, \ | 781 | perf_tp_event(event_call->id, __addr, __count, entry, \ |
781 | __entry_size); \ | 782 | __entry_size); \ |
782 | \ | 783 | \ |
783 | end_recursion: \ | 784 | end: \ |
784 | trace_buf->recursion--; \ | 785 | perf_swevent_put_recursion_context(recursion); \ |
785 | end: \ | 786 | end_recursion: \ |
786 | local_irq_restore(irq_flags); \ | 787 | local_irq_restore(irq_flags); \ |
787 | \ | 788 | \ |
788 | } | 789 | } |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 718fa939b1a7..aba822722300 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -3880,34 +3880,42 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, | |||
3880 | } | 3880 | } |
3881 | } | 3881 | } |
3882 | 3882 | ||
3883 | static int *perf_swevent_recursion_context(struct perf_cpu_context *cpuctx) | 3883 | /* |
3884 | * Must be called with preemption disabled | ||
3885 | */ | ||
3886 | int perf_swevent_get_recursion_context(int **recursion) | ||
3884 | { | 3887 | { |
3888 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3889 | |||
3885 | if (in_nmi()) | 3890 | if (in_nmi()) |
3886 | return &cpuctx->recursion[3]; | 3891 | *recursion = &cpuctx->recursion[3]; |
3892 | else if (in_irq()) | ||
3893 | *recursion = &cpuctx->recursion[2]; | ||
3894 | else if (in_softirq()) | ||
3895 | *recursion = &cpuctx->recursion[1]; | ||
3896 | else | ||
3897 | *recursion = &cpuctx->recursion[0]; | ||
3887 | 3898 | ||
3888 | if (in_irq()) | 3899 | if (**recursion) |
3889 | return &cpuctx->recursion[2]; | 3900 | return -1; |
3890 | 3901 | ||
3891 | if (in_softirq()) | 3902 | (**recursion)++; |
3892 | return &cpuctx->recursion[1]; | ||
3893 | 3903 | ||
3894 | return &cpuctx->recursion[0]; | 3904 | return 0; |
3895 | } | 3905 | } |
3896 | 3906 | ||
3897 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, | 3907 | void perf_swevent_put_recursion_context(int *recursion) |
3898 | u64 nr, int nmi, | ||
3899 | struct perf_sample_data *data, | ||
3900 | struct pt_regs *regs) | ||
3901 | { | 3908 | { |
3902 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); | 3909 | (*recursion)--; |
3903 | int *recursion = perf_swevent_recursion_context(cpuctx); | 3910 | } |
3904 | struct perf_event_context *ctx; | ||
3905 | |||
3906 | if (*recursion) | ||
3907 | goto out; | ||
3908 | 3911 | ||
3909 | (*recursion)++; | 3912 | static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, |
3910 | barrier(); | 3913 | u64 nr, int nmi, |
3914 | struct perf_sample_data *data, | ||
3915 | struct pt_regs *regs) | ||
3916 | { | ||
3917 | struct perf_event_context *ctx; | ||
3918 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3911 | 3919 | ||
3912 | rcu_read_lock(); | 3920 | rcu_read_lock(); |
3913 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, | 3921 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, |
@@ -3920,12 +3928,25 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id, | |||
3920 | if (ctx) | 3928 | if (ctx) |
3921 | perf_swevent_ctx_event(ctx, type, event_id, nr, nmi, data, regs); | 3929 | perf_swevent_ctx_event(ctx, type, event_id, nr, nmi, data, regs); |
3922 | rcu_read_unlock(); | 3930 | rcu_read_unlock(); |
3931 | } | ||
3923 | 3932 | ||
3924 | barrier(); | 3933 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, |
3925 | (*recursion)--; | 3934 | u64 nr, int nmi, |
3935 | struct perf_sample_data *data, | ||
3936 | struct pt_regs *regs) | ||
3937 | { | ||
3938 | int *recursion; | ||
3939 | |||
3940 | preempt_disable(); | ||
3941 | |||
3942 | if (perf_swevent_get_recursion_context(&recursion)) | ||
3943 | goto out; | ||
3944 | |||
3945 | __do_perf_sw_event(type, event_id, nr, nmi, data, regs); | ||
3926 | 3946 | ||
3947 | perf_swevent_put_recursion_context(recursion); | ||
3927 | out: | 3948 | out: |
3928 | put_cpu_var(perf_cpu_context); | 3949 | preempt_enable(); |
3929 | } | 3950 | } |
3930 | 3951 | ||
3931 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, | 3952 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, |
@@ -4159,7 +4180,8 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4159 | if (!regs) | 4180 | if (!regs) |
4160 | regs = task_pt_regs(current); | 4181 | regs = task_pt_regs(current); |
4161 | 4182 | ||
4162 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | 4183 | /* Trace events already protected against recursion */ |
4184 | __do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | ||
4163 | &data, regs); | 4185 | &data, regs); |
4164 | } | 4186 | } |
4165 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4187 | EXPORT_SYMBOL_GPL(perf_tp_event); |
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index e0d351b01f5a..d9c60f80aa0d 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c | |||
@@ -9,31 +9,33 @@ | |||
9 | #include "trace.h" | 9 | #include "trace.h" |
10 | 10 | ||
11 | 11 | ||
12 | struct perf_trace_buf *perf_trace_buf; | 12 | char *perf_trace_buf; |
13 | EXPORT_SYMBOL_GPL(perf_trace_buf); | 13 | EXPORT_SYMBOL_GPL(perf_trace_buf); |
14 | 14 | ||
15 | struct perf_trace_buf *perf_trace_buf_nmi; | 15 | char *perf_trace_buf_nmi; |
16 | EXPORT_SYMBOL_GPL(perf_trace_buf_nmi); | 16 | EXPORT_SYMBOL_GPL(perf_trace_buf_nmi); |
17 | 17 | ||
18 | typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ; | ||
19 | |||
18 | /* Count the events in use (per event id, not per instance) */ | 20 | /* Count the events in use (per event id, not per instance) */ |
19 | static int total_profile_count; | 21 | static int total_profile_count; |
20 | 22 | ||
21 | static int ftrace_profile_enable_event(struct ftrace_event_call *event) | 23 | static int ftrace_profile_enable_event(struct ftrace_event_call *event) |
22 | { | 24 | { |
23 | struct perf_trace_buf *buf; | 25 | char *buf; |
24 | int ret = -ENOMEM; | 26 | int ret = -ENOMEM; |
25 | 27 | ||
26 | if (atomic_inc_return(&event->profile_count)) | 28 | if (atomic_inc_return(&event->profile_count)) |
27 | return 0; | 29 | return 0; |
28 | 30 | ||
29 | if (!total_profile_count) { | 31 | if (!total_profile_count) { |
30 | buf = alloc_percpu(struct perf_trace_buf); | 32 | buf = (char *)alloc_percpu(perf_trace_t); |
31 | if (!buf) | 33 | if (!buf) |
32 | goto fail_buf; | 34 | goto fail_buf; |
33 | 35 | ||
34 | rcu_assign_pointer(perf_trace_buf, buf); | 36 | rcu_assign_pointer(perf_trace_buf, buf); |
35 | 37 | ||
36 | buf = alloc_percpu(struct perf_trace_buf); | 38 | buf = (char *)alloc_percpu(perf_trace_t); |
37 | if (!buf) | 39 | if (!buf) |
38 | goto fail_buf_nmi; | 40 | goto fail_buf_nmi; |
39 | 41 | ||
@@ -79,7 +81,7 @@ int ftrace_profile_enable(int event_id) | |||
79 | 81 | ||
80 | static void ftrace_profile_disable_event(struct ftrace_event_call *event) | 82 | static void ftrace_profile_disable_event(struct ftrace_event_call *event) |
81 | { | 83 | { |
82 | struct perf_trace_buf *buf, *nmi_buf; | 84 | char *buf, *nmi_buf; |
83 | 85 | ||
84 | if (!atomic_add_negative(-1, &event->profile_count)) | 86 | if (!atomic_add_negative(-1, &event->profile_count)) |
85 | return; | 87 | return; |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 3696476f307d..22e6f68b05b3 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1208,11 +1208,12 @@ 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; | ||
1212 | struct trace_entry *ent; | 1211 | struct trace_entry *ent; |
1213 | int size, __size, i, pc, __cpu; | 1212 | int size, __size, i, pc, __cpu; |
1214 | unsigned long irq_flags; | 1213 | unsigned long irq_flags; |
1214 | char *trace_buf; | ||
1215 | char *raw_data; | 1215 | char *raw_data; |
1216 | int *recursion; | ||
1216 | 1217 | ||
1217 | pc = preempt_count(); | 1218 | pc = preempt_count(); |
1218 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | 1219 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); |
@@ -1227,6 +1228,10 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1227 | * This also protects the rcu read side | 1228 | * This also protects the rcu read side |
1228 | */ | 1229 | */ |
1229 | local_irq_save(irq_flags); | 1230 | local_irq_save(irq_flags); |
1231 | |||
1232 | if (perf_swevent_get_recursion_context(&recursion)) | ||
1233 | goto end_recursion; | ||
1234 | |||
1230 | __cpu = smp_processor_id(); | 1235 | __cpu = smp_processor_id(); |
1231 | 1236 | ||
1232 | if (in_nmi()) | 1237 | if (in_nmi()) |
@@ -1237,18 +1242,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1237 | if (!trace_buf) | 1242 | if (!trace_buf) |
1238 | goto end; | 1243 | goto end; |
1239 | 1244 | ||
1240 | trace_buf = per_cpu_ptr(trace_buf, __cpu); | 1245 | raw_data = 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 | 1246 | ||
1253 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | 1247 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ |
1254 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 1248 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -1263,9 +1257,9 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1263 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1257 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1264 | perf_tp_event(call->id, entry->ip, 1, entry, size); | 1258 | perf_tp_event(call->id, entry->ip, 1, entry, size); |
1265 | 1259 | ||
1266 | end_recursion: | ||
1267 | trace_buf->recursion--; | ||
1268 | end: | 1260 | end: |
1261 | perf_swevent_put_recursion_context(recursion); | ||
1262 | end_recursion: | ||
1269 | local_irq_restore(irq_flags); | 1263 | local_irq_restore(irq_flags); |
1270 | 1264 | ||
1271 | return 0; | 1265 | return 0; |
@@ -1278,10 +1272,11 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1278 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | 1272 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); |
1279 | struct ftrace_event_call *call = &tp->call; | 1273 | struct ftrace_event_call *call = &tp->call; |
1280 | struct kretprobe_trace_entry *entry; | 1274 | struct kretprobe_trace_entry *entry; |
1281 | struct perf_trace_buf *trace_buf; | ||
1282 | struct trace_entry *ent; | 1275 | struct trace_entry *ent; |
1283 | int size, __size, i, pc, __cpu; | 1276 | int size, __size, i, pc, __cpu; |
1284 | unsigned long irq_flags; | 1277 | unsigned long irq_flags; |
1278 | char *trace_buf; | ||
1279 | int *recursion; | ||
1285 | char *raw_data; | 1280 | char *raw_data; |
1286 | 1281 | ||
1287 | pc = preempt_count(); | 1282 | pc = preempt_count(); |
@@ -1297,6 +1292,10 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1297 | * This also protects the rcu read side | 1292 | * This also protects the rcu read side |
1298 | */ | 1293 | */ |
1299 | local_irq_save(irq_flags); | 1294 | local_irq_save(irq_flags); |
1295 | |||
1296 | if (perf_swevent_get_recursion_context(&recursion)) | ||
1297 | goto end_recursion; | ||
1298 | |||
1300 | __cpu = smp_processor_id(); | 1299 | __cpu = smp_processor_id(); |
1301 | 1300 | ||
1302 | if (in_nmi()) | 1301 | if (in_nmi()) |
@@ -1307,18 +1306,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1307 | if (!trace_buf) | 1306 | if (!trace_buf) |
1308 | goto end; | 1307 | goto end; |
1309 | 1308 | ||
1310 | trace_buf = per_cpu_ptr(trace_buf, __cpu); | 1309 | raw_data = 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 | 1310 | ||
1323 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ | 1311 | /* Zero dead bytes from alignment to avoid buffer leak to userspace */ |
1324 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 1312 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -1334,9 +1322,9 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1334 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1322 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); |
1335 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); | 1323 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); |
1336 | 1324 | ||
1337 | end_recursion: | ||
1338 | trace_buf->recursion--; | ||
1339 | end: | 1325 | end: |
1326 | perf_swevent_put_recursion_context(recursion); | ||
1327 | end_recursion: | ||
1340 | local_irq_restore(irq_flags); | 1328 | local_irq_restore(irq_flags); |
1341 | 1329 | ||
1342 | return 0; | 1330 | return 0; |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 51213b0aa81b..0bb934875263 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -477,10 +477,11 @@ 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; | ||
481 | struct syscall_trace_enter *rec; | 480 | struct syscall_trace_enter *rec; |
482 | unsigned long flags; | 481 | unsigned long flags; |
482 | char *trace_buf; | ||
483 | char *raw_data; | 483 | char *raw_data; |
484 | int *recursion; | ||
484 | int syscall_nr; | 485 | int syscall_nr; |
485 | int size; | 486 | int size; |
486 | int cpu; | 487 | int cpu; |
@@ -505,6 +506,9 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
505 | /* Protect the per cpu buffer, begin the rcu read side */ | 506 | /* Protect the per cpu buffer, begin the rcu read side */ |
506 | local_irq_save(flags); | 507 | local_irq_save(flags); |
507 | 508 | ||
509 | if (perf_swevent_get_recursion_context(&recursion)) | ||
510 | goto end_recursion; | ||
511 | |||
508 | cpu = smp_processor_id(); | 512 | cpu = smp_processor_id(); |
509 | 513 | ||
510 | if (in_nmi()) | 514 | if (in_nmi()) |
@@ -515,18 +519,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
515 | if (!trace_buf) | 519 | if (!trace_buf) |
516 | goto end; | 520 | goto end; |
517 | 521 | ||
518 | trace_buf = per_cpu_ptr(trace_buf, cpu); | 522 | raw_data = 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; | ||
530 | 523 | ||
531 | /* zero the dead bytes from align to not leak stack to user */ | 524 | /* zero the dead bytes from align to not leak stack to user */ |
532 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 525 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -539,9 +532,9 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
539 | (unsigned long *)&rec->args); | 532 | (unsigned long *)&rec->args); |
540 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); | 533 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); |
541 | 534 | ||
542 | end_recursion: | ||
543 | trace_buf->recursion--; | ||
544 | end: | 535 | end: |
536 | perf_swevent_put_recursion_context(recursion); | ||
537 | end_recursion: | ||
545 | local_irq_restore(flags); | 538 | local_irq_restore(flags); |
546 | } | 539 | } |
547 | 540 | ||
@@ -588,10 +581,11 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
588 | { | 581 | { |
589 | struct syscall_metadata *sys_data; | 582 | struct syscall_metadata *sys_data; |
590 | struct syscall_trace_exit *rec; | 583 | struct syscall_trace_exit *rec; |
591 | struct perf_trace_buf *trace_buf; | ||
592 | unsigned long flags; | 584 | unsigned long flags; |
593 | int syscall_nr; | 585 | int syscall_nr; |
586 | char *trace_buf; | ||
594 | char *raw_data; | 587 | char *raw_data; |
588 | int *recursion; | ||
595 | int size; | 589 | int size; |
596 | int cpu; | 590 | int cpu; |
597 | 591 | ||
@@ -617,6 +611,10 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
617 | 611 | ||
618 | /* Protect the per cpu buffer, begin the rcu read side */ | 612 | /* Protect the per cpu buffer, begin the rcu read side */ |
619 | local_irq_save(flags); | 613 | local_irq_save(flags); |
614 | |||
615 | if (perf_swevent_get_recursion_context(&recursion)) | ||
616 | goto end_recursion; | ||
617 | |||
620 | cpu = smp_processor_id(); | 618 | cpu = smp_processor_id(); |
621 | 619 | ||
622 | if (in_nmi()) | 620 | if (in_nmi()) |
@@ -627,18 +625,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
627 | if (!trace_buf) | 625 | if (!trace_buf) |
628 | goto end; | 626 | goto end; |
629 | 627 | ||
630 | trace_buf = per_cpu_ptr(trace_buf, cpu); | 628 | raw_data = 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; | ||
642 | 629 | ||
643 | /* zero the dead bytes from align to not leak stack to user */ | 630 | /* zero the dead bytes from align to not leak stack to user */ |
644 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | 631 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; |
@@ -652,9 +639,9 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
652 | 639 | ||
653 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); | 640 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); |
654 | 641 | ||
655 | end_recursion: | ||
656 | trace_buf->recursion--; | ||
657 | end: | 642 | end: |
643 | perf_swevent_put_recursion_context(recursion); | ||
644 | end_recursion: | ||
658 | local_irq_restore(flags); | 645 | local_irq_restore(flags); |
659 | } | 646 | } |
660 | 647 | ||