aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2010-06-03 05:21:20 -0400
committerIngo Molnar <mingo@elte.hu>2010-06-03 11:03:08 -0400
commitc6df8d5ab87a246942d138321e1721edbb69f6e1 (patch)
tree4fa2965d148c3e7ea456ab889d278d5c16d25d17 /kernel/perf_event.c
parentda3fd1a0010ccc9fe6fd5ae2b9e85e1aacc03e4d (diff)
perf: Fix crash in swevents
Frederic reported that because swevents handling doesn't disable IRQs anymore, we can get a recursion of perf_adjust_period(), once from overflow handling and once from the tick. If both call ->disable, we get a double hlist_del_rcu() and trigger a LIST_POISON2 dereference. Since we don't actually need to stop/start a swevent to re-programm the hardware (lack of hardware to program), simply nop out these callbacks for the swevent pmu. Reported-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1275557609.27810.35218.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 858f56fa2432..31d6afe92594 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -4055,13 +4055,6 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
4055 } 4055 }
4056} 4056}
4057 4057
4058static void perf_swevent_unthrottle(struct perf_event *event)
4059{
4060 /*
4061 * Nothing to do, we already reset hwc->interrupts.
4062 */
4063}
4064
4065static void perf_swevent_add(struct perf_event *event, u64 nr, 4058static void perf_swevent_add(struct perf_event *event, u64 nr,
4066 int nmi, struct perf_sample_data *data, 4059 int nmi, struct perf_sample_data *data,
4067 struct pt_regs *regs) 4060 struct pt_regs *regs)
@@ -4276,11 +4269,22 @@ static void perf_swevent_disable(struct perf_event *event)
4276 hlist_del_rcu(&event->hlist_entry); 4269 hlist_del_rcu(&event->hlist_entry);
4277} 4270}
4278 4271
4272static void perf_swevent_void(struct perf_event *event)
4273{
4274}
4275
4276static int perf_swevent_int(struct perf_event *event)
4277{
4278 return 0;
4279}
4280
4279static const struct pmu perf_ops_generic = { 4281static const struct pmu perf_ops_generic = {
4280 .enable = perf_swevent_enable, 4282 .enable = perf_swevent_enable,
4281 .disable = perf_swevent_disable, 4283 .disable = perf_swevent_disable,
4284 .start = perf_swevent_int,
4285 .stop = perf_swevent_void,
4282 .read = perf_swevent_read, 4286 .read = perf_swevent_read,
4283 .unthrottle = perf_swevent_unthrottle, 4287 .unthrottle = perf_swevent_void, /* hwc->interrupts already reset */
4284}; 4288};
4285 4289
4286/* 4290/*
@@ -4561,8 +4565,10 @@ static int swevent_hlist_get(struct perf_event *event)
4561static const struct pmu perf_ops_tracepoint = { 4565static const struct pmu perf_ops_tracepoint = {
4562 .enable = perf_trace_enable, 4566 .enable = perf_trace_enable,
4563 .disable = perf_trace_disable, 4567 .disable = perf_trace_disable,
4568 .start = perf_swevent_int,
4569 .stop = perf_swevent_void,
4564 .read = perf_swevent_read, 4570 .read = perf_swevent_read,
4565 .unthrottle = perf_swevent_unthrottle, 4571 .unthrottle = perf_swevent_void,
4566}; 4572};
4567 4573
4568static int perf_tp_filter_match(struct perf_event *event, 4574static int perf_tp_filter_match(struct perf_event *event,