diff options
-rw-r--r-- | include/linux/perf_event.h | 8 | ||||
-rw-r--r-- | include/trace/ftrace.h | 17 | ||||
-rw-r--r-- | kernel/perf_event.c | 71 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 14 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 14 |
5 files changed, 61 insertions, 63 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 74e98b1d3391..43adbd7f0010 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -874,8 +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); | 877 | extern int perf_swevent_get_recursion_context(void); |
878 | extern void perf_swevent_put_recursion_context(int *recursion); | 878 | extern void perf_swevent_put_recursion_context(int rctx); |
879 | #else | 879 | #else |
880 | static inline void | 880 | static inline void |
881 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } | 881 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } |
@@ -904,8 +904,8 @@ static inline void perf_event_mmap(struct vm_area_struct *vma) { } | |||
904 | static inline void perf_event_comm(struct task_struct *tsk) { } | 904 | static inline void perf_event_comm(struct task_struct *tsk) { } |
905 | static inline void perf_event_fork(struct task_struct *tsk) { } | 905 | static inline void perf_event_fork(struct task_struct *tsk) { } |
906 | 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; } | 907 | static inline int perf_swevent_get_recursion_context(void) { return -1; } |
908 | static void perf_swevent_put_recursion_context(int *recursion) { } | 908 | static inline void perf_swevent_put_recursion_context(int rctx) { } |
909 | 909 | ||
910 | #endif | 910 | #endif |
911 | 911 | ||
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index c222ef5238bf..c3417c13e3ed 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -724,8 +724,8 @@ __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); \ | 727 | extern int perf_swevent_get_recursion_context(void); \ |
728 | extern void perf_swevent_put_recursion_context(int *recursion); \ | 728 | extern void perf_swevent_put_recursion_context(int rctx); \ |
729 | struct ftrace_event_call *event_call = &event_##call; \ | 729 | struct ftrace_event_call *event_call = &event_##call; \ |
730 | extern void perf_tp_event(int, u64, u64, void *, int); \ | 730 | extern void perf_tp_event(int, u64, u64, void *, int); \ |
731 | struct ftrace_raw_##call *entry; \ | 731 | struct ftrace_raw_##call *entry; \ |
@@ -736,8 +736,8 @@ static void ftrace_profile_##call(proto) \ | |||
736 | int __data_size; \ | 736 | int __data_size; \ |
737 | char *trace_buf; \ | 737 | char *trace_buf; \ |
738 | char *raw_data; \ | 738 | char *raw_data; \ |
739 | int *recursion; \ | ||
740 | int __cpu; \ | 739 | int __cpu; \ |
740 | int rctx; \ | ||
741 | int pc; \ | 741 | int pc; \ |
742 | \ | 742 | \ |
743 | pc = preempt_count(); \ | 743 | pc = preempt_count(); \ |
@@ -753,8 +753,9 @@ static void ftrace_profile_##call(proto) \ | |||
753 | \ | 753 | \ |
754 | local_irq_save(irq_flags); \ | 754 | local_irq_save(irq_flags); \ |
755 | \ | 755 | \ |
756 | if (perf_swevent_get_recursion_context(&recursion)) \ | 756 | rctx = perf_swevent_get_recursion_context(); \ |
757 | goto end_recursion; \ | 757 | if (rctx < 0) \ |
758 | goto end_recursion; \ | ||
758 | \ | 759 | \ |
759 | __cpu = smp_processor_id(); \ | 760 | __cpu = smp_processor_id(); \ |
760 | \ | 761 | \ |
@@ -781,9 +782,9 @@ static void ftrace_profile_##call(proto) \ | |||
781 | perf_tp_event(event_call->id, __addr, __count, entry, \ | 782 | perf_tp_event(event_call->id, __addr, __count, entry, \ |
782 | __entry_size); \ | 783 | __entry_size); \ |
783 | \ | 784 | \ |
784 | end: \ | 785 | end: \ |
785 | perf_swevent_put_recursion_context(recursion); \ | 786 | perf_swevent_put_recursion_context(rctx); \ |
786 | end_recursion: \ | 787 | end_recursion: \ |
787 | local_irq_restore(irq_flags); \ | 788 | local_irq_restore(irq_flags); \ |
788 | \ | 789 | \ |
789 | } | 790 | } |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 50f11b5f8c3d..0b0d5f72fe7d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -3869,45 +3869,50 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, | |||
3869 | } | 3869 | } |
3870 | } | 3870 | } |
3871 | 3871 | ||
3872 | /* | 3872 | int perf_swevent_get_recursion_context(void) |
3873 | * Must be called with preemption disabled | ||
3874 | */ | ||
3875 | int perf_swevent_get_recursion_context(int **recursion) | ||
3876 | { | 3873 | { |
3877 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | 3874 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); |
3875 | int rctx; | ||
3878 | 3876 | ||
3879 | if (in_nmi()) | 3877 | if (in_nmi()) |
3880 | *recursion = &cpuctx->recursion[3]; | 3878 | rctx = 3; |
3881 | else if (in_irq()) | 3879 | else if (in_irq()) |
3882 | *recursion = &cpuctx->recursion[2]; | 3880 | rctx = 2; |
3883 | else if (in_softirq()) | 3881 | else if (in_softirq()) |
3884 | *recursion = &cpuctx->recursion[1]; | 3882 | rctx = 1; |
3885 | else | 3883 | else |
3886 | *recursion = &cpuctx->recursion[0]; | 3884 | rctx = 0; |
3887 | 3885 | ||
3888 | if (**recursion) | 3886 | if (cpuctx->recursion[rctx]) { |
3887 | put_cpu_var(perf_cpu_context); | ||
3889 | return -1; | 3888 | return -1; |
3889 | } | ||
3890 | 3890 | ||
3891 | (**recursion)++; | 3891 | cpuctx->recursion[rctx]++; |
3892 | barrier(); | ||
3892 | 3893 | ||
3893 | return 0; | 3894 | return rctx; |
3894 | } | 3895 | } |
3895 | EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); | 3896 | EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); |
3896 | 3897 | ||
3897 | void perf_swevent_put_recursion_context(int *recursion) | 3898 | void perf_swevent_put_recursion_context(int rctx) |
3898 | { | 3899 | { |
3899 | (*recursion)--; | 3900 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); |
3901 | barrier(); | ||
3902 | cpuctx->recursion[rctx]++; | ||
3903 | put_cpu_var(perf_cpu_context); | ||
3900 | } | 3904 | } |
3901 | EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); | 3905 | EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); |
3902 | 3906 | ||
3903 | static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, | 3907 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, |
3904 | u64 nr, int nmi, | 3908 | u64 nr, int nmi, |
3905 | struct perf_sample_data *data, | 3909 | struct perf_sample_data *data, |
3906 | struct pt_regs *regs) | 3910 | struct pt_regs *regs) |
3907 | { | 3911 | { |
3912 | struct perf_cpu_context *cpuctx; | ||
3908 | struct perf_event_context *ctx; | 3913 | struct perf_event_context *ctx; |
3909 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3910 | 3914 | ||
3915 | cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3911 | rcu_read_lock(); | 3916 | rcu_read_lock(); |
3912 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, | 3917 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, |
3913 | nr, nmi, data, regs); | 3918 | nr, nmi, data, regs); |
@@ -3921,34 +3926,22 @@ static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, | |||
3921 | rcu_read_unlock(); | 3926 | rcu_read_unlock(); |
3922 | } | 3927 | } |
3923 | 3928 | ||
3924 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, | ||
3925 | u64 nr, int nmi, | ||
3926 | struct perf_sample_data *data, | ||
3927 | struct pt_regs *regs) | ||
3928 | { | ||
3929 | int *recursion; | ||
3930 | |||
3931 | preempt_disable(); | ||
3932 | |||
3933 | if (perf_swevent_get_recursion_context(&recursion)) | ||
3934 | goto out; | ||
3935 | |||
3936 | __do_perf_sw_event(type, event_id, nr, nmi, data, regs); | ||
3937 | |||
3938 | perf_swevent_put_recursion_context(recursion); | ||
3939 | out: | ||
3940 | preempt_enable(); | ||
3941 | } | ||
3942 | |||
3943 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, | 3929 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, |
3944 | struct pt_regs *regs, u64 addr) | 3930 | struct pt_regs *regs, u64 addr) |
3945 | { | 3931 | { |
3946 | struct perf_sample_data data; | 3932 | struct perf_sample_data data; |
3933 | int rctx; | ||
3934 | |||
3935 | rctx = perf_swevent_get_recursion_context(); | ||
3936 | if (rctx < 0) | ||
3937 | return; | ||
3947 | 3938 | ||
3948 | data.addr = addr; | 3939 | data.addr = addr; |
3949 | data.raw = NULL; | 3940 | data.raw = NULL; |
3950 | 3941 | ||
3951 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); | 3942 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); |
3943 | |||
3944 | perf_swevent_put_recursion_context(rctx); | ||
3952 | } | 3945 | } |
3953 | 3946 | ||
3954 | static void perf_swevent_read(struct perf_event *event) | 3947 | static void perf_swevent_read(struct perf_event *event) |
@@ -4172,7 +4165,7 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4172 | regs = task_pt_regs(current); | 4165 | regs = task_pt_regs(current); |
4173 | 4166 | ||
4174 | /* Trace events already protected against recursion */ | 4167 | /* Trace events already protected against recursion */ |
4175 | __do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | 4168 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, |
4176 | &data, regs); | 4169 | &data, regs); |
4177 | } | 4170 | } |
4178 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4171 | EXPORT_SYMBOL_GPL(perf_tp_event); |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 22e6f68b05b3..79ce6a2bd74f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -1213,7 +1213,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1213 | unsigned long irq_flags; | 1213 | unsigned long irq_flags; |
1214 | char *trace_buf; | 1214 | char *trace_buf; |
1215 | char *raw_data; | 1215 | char *raw_data; |
1216 | int *recursion; | 1216 | int rctx; |
1217 | 1217 | ||
1218 | pc = preempt_count(); | 1218 | pc = preempt_count(); |
1219 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | 1219 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); |
@@ -1229,7 +1229,8 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1229 | */ | 1229 | */ |
1230 | local_irq_save(irq_flags); | 1230 | local_irq_save(irq_flags); |
1231 | 1231 | ||
1232 | if (perf_swevent_get_recursion_context(&recursion)) | 1232 | rctx = perf_swevent_get_recursion_context(); |
1233 | if (rctx < 0) | ||
1233 | goto end_recursion; | 1234 | goto end_recursion; |
1234 | 1235 | ||
1235 | __cpu = smp_processor_id(); | 1236 | __cpu = smp_processor_id(); |
@@ -1258,7 +1259,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, | |||
1258 | perf_tp_event(call->id, entry->ip, 1, entry, size); | 1259 | perf_tp_event(call->id, entry->ip, 1, entry, size); |
1259 | 1260 | ||
1260 | end: | 1261 | end: |
1261 | perf_swevent_put_recursion_context(recursion); | 1262 | perf_swevent_put_recursion_context(rctx); |
1262 | end_recursion: | 1263 | end_recursion: |
1263 | local_irq_restore(irq_flags); | 1264 | local_irq_restore(irq_flags); |
1264 | 1265 | ||
@@ -1276,8 +1277,8 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1276 | int size, __size, i, pc, __cpu; | 1277 | int size, __size, i, pc, __cpu; |
1277 | unsigned long irq_flags; | 1278 | unsigned long irq_flags; |
1278 | char *trace_buf; | 1279 | char *trace_buf; |
1279 | int *recursion; | ||
1280 | char *raw_data; | 1280 | char *raw_data; |
1281 | int rctx; | ||
1281 | 1282 | ||
1282 | pc = preempt_count(); | 1283 | pc = preempt_count(); |
1283 | __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); | 1284 | __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); |
@@ -1293,7 +1294,8 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1293 | */ | 1294 | */ |
1294 | local_irq_save(irq_flags); | 1295 | local_irq_save(irq_flags); |
1295 | 1296 | ||
1296 | if (perf_swevent_get_recursion_context(&recursion)) | 1297 | rctx = perf_swevent_get_recursion_context(); |
1298 | if (rctx < 0) | ||
1297 | goto end_recursion; | 1299 | goto end_recursion; |
1298 | 1300 | ||
1299 | __cpu = smp_processor_id(); | 1301 | __cpu = smp_processor_id(); |
@@ -1323,7 +1325,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | |||
1323 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); | 1325 | perf_tp_event(call->id, entry->ret_ip, 1, entry, size); |
1324 | 1326 | ||
1325 | end: | 1327 | end: |
1326 | perf_swevent_put_recursion_context(recursion); | 1328 | perf_swevent_put_recursion_context(rctx); |
1327 | end_recursion: | 1329 | end_recursion: |
1328 | local_irq_restore(irq_flags); | 1330 | local_irq_restore(irq_flags); |
1329 | 1331 | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 41b6dd963daa..9189cbe86079 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -481,8 +481,8 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
481 | unsigned long flags; | 481 | unsigned long flags; |
482 | char *trace_buf; | 482 | char *trace_buf; |
483 | char *raw_data; | 483 | char *raw_data; |
484 | int *recursion; | ||
485 | int syscall_nr; | 484 | int syscall_nr; |
485 | int rctx; | ||
486 | int size; | 486 | int size; |
487 | int cpu; | 487 | int cpu; |
488 | 488 | ||
@@ -506,7 +506,8 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
506 | /* Protect the per cpu buffer, begin the rcu read side */ | 506 | /* Protect the per cpu buffer, begin the rcu read side */ |
507 | local_irq_save(flags); | 507 | local_irq_save(flags); |
508 | 508 | ||
509 | if (perf_swevent_get_recursion_context(&recursion)) | 509 | rctx = perf_swevent_get_recursion_context(); |
510 | if (rctx < 0) | ||
510 | goto end_recursion; | 511 | goto end_recursion; |
511 | 512 | ||
512 | cpu = smp_processor_id(); | 513 | cpu = smp_processor_id(); |
@@ -530,7 +531,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
530 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); | 531 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); |
531 | 532 | ||
532 | end: | 533 | end: |
533 | perf_swevent_put_recursion_context(recursion); | 534 | perf_swevent_put_recursion_context(rctx); |
534 | end_recursion: | 535 | end_recursion: |
535 | local_irq_restore(flags); | 536 | local_irq_restore(flags); |
536 | } | 537 | } |
@@ -582,7 +583,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
582 | int syscall_nr; | 583 | int syscall_nr; |
583 | char *trace_buf; | 584 | char *trace_buf; |
584 | char *raw_data; | 585 | char *raw_data; |
585 | int *recursion; | 586 | int rctx; |
586 | int size; | 587 | int size; |
587 | int cpu; | 588 | int cpu; |
588 | 589 | ||
@@ -609,7 +610,8 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
609 | /* Protect the per cpu buffer, begin the rcu read side */ | 610 | /* Protect the per cpu buffer, begin the rcu read side */ |
610 | local_irq_save(flags); | 611 | local_irq_save(flags); |
611 | 612 | ||
612 | if (perf_swevent_get_recursion_context(&recursion)) | 613 | rctx = perf_swevent_get_recursion_context(); |
614 | if (rctx < 0) | ||
613 | goto end_recursion; | 615 | goto end_recursion; |
614 | 616 | ||
615 | cpu = smp_processor_id(); | 617 | cpu = smp_processor_id(); |
@@ -634,7 +636,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
634 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); | 636 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); |
635 | 637 | ||
636 | end: | 638 | end: |
637 | perf_swevent_put_recursion_context(recursion); | 639 | perf_swevent_put_recursion_context(rctx); |
638 | end_recursion: | 640 | end_recursion: |
639 | local_irq_restore(flags); | 641 | local_irq_restore(flags); |
640 | } | 642 | } |