From: Dave Aldridge Date: Fri, 24 Jun 2016 13:17:25 +0000 (-0700) Subject: sparc64: Fix the watchdog corrupting performance counters X-Git-Tag: v4.1.12-92~12^2~6 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8b28df9930252181c8acb43fe8a8f1e6274cd03a;p=users%2Fjedix%2Flinux-maple.git sparc64: Fix the watchdog corrupting performance counters There is a race condition in the perf_event_grab_pmc() which means that we do not increment the active_events count correctly when a new event is added. Ultimately, we end up with a negative value for the active_event count. This means that the next time we try and add a new event the watchdog will not be stopped correctly and corruption of the performance count will be observed. Note: In sparc64 land the watchdog is implemented using one of the performance counters. This issue is fixed by moving the mutex lock to make sure it encompasses the whole critical section in the perf_event_grab_pmc(). Orabug: 23106709 Signed-off-by: Dave Aldridge Signed-off-by: Rob Gardner (cherry picked from commit 54ed00318fec5db3fab1b035ade5d95926d84799) (cherry picked from commit d9ad125578c9f2fa015beb9dc10bd3d1eb9004ec) Signed-off-by: Allen Pais --- diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 9217e38ebbd76..aa7046572dc39 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1220,10 +1220,12 @@ static void perf_stop_nmi_watchdog(void *unused) static void perf_event_grab_pmc(void) { - if (atomic_inc_not_zero(&active_events)) + mutex_lock(&pmc_grab_mutex); + if (atomic_inc_not_zero(&active_events)) { + mutex_unlock(&pmc_grab_mutex); return; + } - mutex_lock(&pmc_grab_mutex); if (atomic_read(&active_events) == 0) { if (atomic_read(&nmi_active) > 0) { on_each_cpu(perf_stop_nmi_watchdog, NULL, 1); @@ -1241,6 +1243,15 @@ static void perf_event_release_pmc(void) on_each_cpu(start_nmi_watchdog, NULL, 1); mutex_unlock(&pmc_grab_mutex); } + + /* If the active_events count goes negative then + * perf_event_grab_pmc() will not disable the watchdog correctly + * and we end up with the watchdog 'corrupting' a performance + * counter whilst it is being used to count some other event + */ + WARN(atomic_read(&active_events) < 0, + "cpu%d: active_events count is negative !\n", + smp_processor_id()); } static const struct perf_event_map *sparc_map_cache_event(u64 config)