From 8afa5f8798676e277180ee6e5030c4d05ff28bc4 Mon Sep 17 00:00:00 2001 From: Veena Sambasivan Date: Thu, 19 May 2016 18:47:15 -0700 Subject: [PATCH] msm: perf: Do not allocate new hw_event if event is duplicate. During a perf_event_enable, kernel/events/core.c calls pmu->add() which is platform implementation(arch/arm/kernel/perf_event.c). Due to the duplicate constraints, arch/arm/mach-msm/perf_event_msm_krait_l2.c drivers marks the event as OFF but returns TRUE to perf_event.c which goes ahead and allocates the hw_event and enables it. Since event is marked OFF, kernel events core will try to enable this event again during next perf_event_enable. Which results in same event enabled on multiple hw_events. But during the perf_release, event struct is freed and only one hw_event is released. This results in dereferencing the invalid pointer and hence the crash. Fix this by returning error in case of constraint event duplicate. Hence avoiding the same event programmed on multiple hw event counters. Change-Id: Ia3360be027dfe87ac753191ffe7e0bc947e72455 Signed-off-by: Arun KS Signed-off-by: Veena Sambasivan --- arch/arm/kernel/perf_event.c | 1 + arch/arm/mach-msm/perf_event_msm_krait_l2.c | 4 +++- arch/arm/mach-msm/perf_event_msm_l2.c | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 2f04348d62f0..1d9f706e8180 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -300,6 +300,7 @@ armpmu_add(struct perf_event *event, int flags) pr_err("Event: %llx failed constraint check.\n", event->attr.config); event->state = PERF_EVENT_STATE_OFF; + err = -EPERM; goto out; } diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c index 048f024497e5..ce7d95de3908 100644 --- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c +++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c @@ -503,8 +503,10 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event) * This sets the event OFF on all but one * CPU. */ - if (!(event->cpu < 0)) + if (!(event->cpu < 0)) { event->state = PERF_EVENT_STATE_OFF; + err = -EPERM; + } } out: raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags); diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c index f78487a74349..93695e2b5c84 100644 --- a/arch/arm/mach-msm/perf_event_msm_l2.c +++ b/arch/arm/mach-msm/perf_event_msm_l2.c @@ -836,8 +836,10 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event) * This sets the event OFF on all but one * CPU. */ - if (!(event->cpu < 0)) + if (!(event->cpu < 0)) { event->state = PERF_EVENT_STATE_OFF; + err = -EPERM; + } } out: