aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c71
1 files changed, 32 insertions, 39 deletions
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/* 3872int perf_swevent_get_recursion_context(void)
3873 * Must be called with preemption disabled
3874 */
3875int 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}
3895EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); 3896EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
3896 3897
3897void perf_swevent_put_recursion_context(int *recursion) 3898void 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}
3901EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); 3905EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
3902 3906
3903static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, 3907static 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
3924static 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);
3939out:
3940 preempt_enable();
3941}
3942
3943void __perf_sw_event(u32 event_id, u64 nr, int nmi, 3929void __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
3954static void perf_swevent_read(struct perf_event *event) 3947static 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}
4178EXPORT_SYMBOL_GPL(perf_tp_event); 4171EXPORT_SYMBOL_GPL(perf_tp_event);