summaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-11-22 05:26:55 +0100
committerIngo Molnar <mingo@elte.hu>2009-11-22 09:03:42 +0100
commitce71b9df8893ec954e56c5979df6da274f20f65e (patch)
tree76e8a5e33393c2f4fca4083628fc142dcbb55250 /kernel/perf_event.c
parente25613683bd5c46d3e8c8ae6416dccc9f357dcdc (diff)
downloadlinux-ce71b9df8893ec954e56c5979df6da274f20f65e.tar.bz2
tracing: Use the perf recursion protection from trace event
When we commit a trace to perf, we first check if we are recursing in the same buffer so that we don't mess-up the buffer with a recursing trace. But later on, we do the same check from perf to avoid commit recursion. The recursion check is desired early before we touch the buffer but we want to do this check only once. Then export the recursion protection from perf and use it from the trace events before submitting a trace. v2: Put appropriate Reported-by tag Reported-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: Jason Baron <jbaron@redhat.com> LKML-Reference: <1258864015-10579-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
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,
}
}
-static int *perf_swevent_recursion_context(struct perf_cpu_context *cpuctx)
+/*
+ * Must be called with preemption disabled
+ */
+int perf_swevent_get_recursion_context(int **recursion)
{
+ struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
+
if (in_nmi())
- return &cpuctx->recursion[3];
+ *recursion = &cpuctx->recursion[3];
+ else if (in_irq())
+ *recursion = &cpuctx->recursion[2];
+ else if (in_softirq())
+ *recursion = &cpuctx->recursion[1];
+ else
+ *recursion = &cpuctx->recursion[0];
- if (in_irq())
- return &cpuctx->recursion[2];
+ if (**recursion)
+ return -1;
- if (in_softirq())
- return &cpuctx->recursion[1];
+ (**recursion)++;
- return &cpuctx->recursion[0];
+ return 0;
}
-static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
- u64 nr, int nmi,
- struct perf_sample_data *data,
- struct pt_regs *regs)
+void perf_swevent_put_recursion_context(int *recursion)
{
- struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
- int *recursion = perf_swevent_recursion_context(cpuctx);
- struct perf_event_context *ctx;
-
- if (*recursion)
- goto out;
+ (*recursion)--;
+}
- (*recursion)++;
- barrier();
+static void __do_perf_sw_event(enum perf_type_id type, u32 event_id,
+ u64 nr, int nmi,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ struct perf_event_context *ctx;
+ struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
rcu_read_lock();
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,
if (ctx)
perf_swevent_ctx_event(ctx, type, event_id, nr, nmi, data, regs);
rcu_read_unlock();
+}
- barrier();
- (*recursion)--;
+static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
+ u64 nr, int nmi,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ int *recursion;
+
+ preempt_disable();
+
+ if (perf_swevent_get_recursion_context(&recursion))
+ goto out;
+
+ __do_perf_sw_event(type, event_id, nr, nmi, data, regs);
+ perf_swevent_put_recursion_context(recursion);
out:
- put_cpu_var(perf_cpu_context);
+ preempt_enable();
}
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,
if (!regs)
regs = task_pt_regs(current);
- do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
+ /* Trace events already protected against recursion */
+ __do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
&data, regs);
}
EXPORT_SYMBOL_GPL(perf_tp_event);