History

softlockup: fix NMI hangs due to lock race - 2.6.26-rc regression

The touch_nmi_watchdog() routine on x86 ultimately calls touch_softlockup_watchdog(). The problem is that to touch the softlockup watchdog, the cpu_clock code has to be called which could involve multiple cpu locks and can lead to a hard hang if one of the locks is held by a processor that is not going to return anytime soon (such as could be the case with kgdb or perhaps even with some other kind of exception). This patch causes the public version of the touch_softlockup_watchdog() to defer the cpu clock access to a later point. The test case for this problem is to use the following kernel config options: CONFIG_KGDB_TESTS=y CONFIG_KGDB_TESTS_ON_BOOT=y CONFIG_KGDB_TESTS_BOOT_STRING="V1F100I100000" It should be noted that kgdb test suite and these options were not available until 2.6.26-rc2, so it was necessary to patch the kgdb test suite during the bisection. I would consider this patch a regression fix because the problem first appeared in commit 27ec4407790d075c325e1f4da0a19c56953cce23 when some logic was added to try to periodically sync the clocks. It was possible to work around this particular problem by simply not performing the sync anytime the system was in a critical context. This was ok until commit 3e51f33fcc7f55e6df25d15b55ed10c8b4da84cd, which added config option CONFIG_HAVE_UNSTABLE_SCHED_CLOCK and some multi-cpu locks to sync the clocks. It became clear that accessing this code from an nmi was the source of the lockups. Avoiding the access to the low level clock code from an code inside the NMI processing also fixed the problem with the 27ec44... commit.

Jason Wessel committed 18 years ago

Commit 9c106c11 parent afd38001 file · +10 −5Browse files

Unified · Split

kernel/softlockup.c+10−5
@@ -49,12 +49,17 @@ static unsigned long get_timestamp(int this_cpu) · 48 unmodified lines
4949 return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
5050 }
5151
52−void touch_softlockup_watchdog(void)
52+static void __touch_softlockup_watchdog(void)
5353 {
5454 int this_cpu = raw_smp_processor_id();
5555
5656 __raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
5757 }
58+
59+void touch_softlockup_watchdog(void)
60+{
61+ __raw_get_cpu_var(touch_timestamp) = 0;
62+}
5863 EXPORT_SYMBOL(touch_softlockup_watchdog);
5964
6065 void touch_all_softlockup_watchdogs(void)
@@ -80,7 +85,7 @@ void softlockup_tick(void) · 19 unmodified lines
8085 unsigned long now;
8186
8287 if (touch_timestamp == 0) {
83− touch_softlockup_watchdog();
88+ __touch_softlockup_watchdog();
8489 return;
8590 }
8691
@@ -95,7 +100,7 @@ void softlockup_tick(void) · 8 unmodified lines
95100
96101 /* do not print during early bootup: */
97102 if (unlikely(system_state != SYSTEM_RUNNING)) {
98− touch_softlockup_watchdog();
103+ __touch_softlockup_watchdog();
99104 return;
100105 }
101106
@@ -214,7 +219,7 @@ static int watchdog(void *__bind_cpu) · 112 unmodified lines
214219 sched_setscheduler(current, SCHED_FIFO, &param);
215220
216221 /* initialize timestamp */
217− touch_softlockup_watchdog();
222+ __touch_softlockup_watchdog();
218223
219224 set_current_state(TASK_INTERRUPTIBLE);
220225 /*
@@ -223,7 +228,7 @@ static int watchdog(void *__bind_cpu) · 2 unmodified lines
223228 * debug-printout triggers in softlockup_tick().
224229 */
225230 while (!kthread_should_stop()) {
226− touch_softlockup_watchdog();
231+ __touch_softlockup_watchdog();
227232 schedule();
228233
229234 if (kthread_should_stop())