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.c68
1 files changed, 45 insertions, 23 deletions
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
3883static int *perf_swevent_recursion_context(struct perf_cpu_context *cpuctx) 3883/*
3884 * Must be called with preemption disabled
3885 */
3886int 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
3897static void do_perf_sw_event(enum perf_type_id type, u32 event_id, 3907void 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)++; 3912static 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(); 3933static 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);
3927out: 3948out:
3928 put_cpu_var(perf_cpu_context); 3949 preempt_enable();
3929} 3950}
3930 3951
3931void __perf_sw_event(u32 event_id, u64 nr, int nmi, 3952void __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}
4165EXPORT_SYMBOL_GPL(perf_tp_event); 4187EXPORT_SYMBOL_GPL(perf_tp_event);