]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: Fix the watchdog corrupting performance counters
authorDave Aldridge <david.j.aldridge@oracle.com>
Fri, 24 Jun 2016 13:17:25 +0000 (06:17 -0700)
committerAllen Pais <allen.pais@oracle.com>
Sun, 22 Jan 2017 15:38:10 +0000 (21:08 +0530)
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 <david.j.aldridge@oracle.com>
Signed-off-by: Rob Gardner <rob.gardner@oracle.com>
(cherry picked from commit 54ed00318fec5db3fab1b035ade5d95926d84799)
(cherry picked from commit d9ad125578c9f2fa015beb9dc10bd3d1eb9004ec)
Signed-off-by: Allen Pais <allen.pais@oracle.com>
arch/sparc/kernel/perf_event.c

index 9217e38ebbd76d4e7470255051038b3fd0295dd6..aa7046572dc394222ba6f5f0179a29130753b5b8 100644 (file)
@@ -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)