History

watchdog: update saved interrupts during check

Currently, arch_touch_nmi_watchdog() causes an early return that skips updating hrtimer_interrupts_saved. This leads to stale comparisons and delayed lockup detection. I found this issue because in our system the serial console is fairly chatty. For example, the 8250 console driver frequently calls touch_nmi_watchdog() via console_write(). If a CPU locks up after a timer interrupt but before next watchdog check, we see the following sequence: * watchdog_hardlockup_check() saves counter (e.g., 1000) * Timer runs and updates the counter (1001) * touch_nmi_watchdog() is called * CPU locks up * 10s pass: check() notices touch, returns early, skips update * 10s pass: check() saves counter (1001) * 10s pass: check() finally detects lockup This delays detection to 30 seconds. With this fix, we detect the lockup in 20 seconds.

Mayank Rungta committed 8 months ago

Commit 746bb7f1 parent 3e811ca1 file · +13 −5Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/watchdog.c+13−5
@@ -159,21 +159,28 @@ void watchdog_hardlockup_touch_cpu(unsigned int cpu) · 158 unmodified lines
159159 per_cpu(watchdog_hardlockup_touched, cpu) = true;
160160 }
161161
162−static bool is_hardlockup(unsigned int cpu)
162+static void watchdog_hardlockup_update(unsigned int cpu)
163163 {
164164 int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
165165
166− if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
167− return true;
168−
169166 /*
170167 * NOTE: we don't need any fancy atomic_t or READ_ONCE/WRITE_ONCE
171168 * for hrtimer_interrupts_saved. hrtimer_interrupts_saved is
172169 * written/read by a single CPU.
173170 */
174171 per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
172+}
173+
174+static bool is_hardlockup(unsigned int cpu)
175+{
176+ int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
177+
178+ if (per_cpu(hrtimer_interrupts_saved, cpu) != hrint) {
179+ watchdog_hardlockup_update(cpu);
180+ return false;
181+ }
175182
176− return false;
183+ return true;
177184 }
178185
179186 static void watchdog_hardlockup_kick(void)
@@ -191,6 +198,7 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs) · 11 unmodified lines
191198 unsigned long flags;
192199
193200 if (per_cpu(watchdog_hardlockup_touched, cpu)) {
201+ watchdog_hardlockup_update(cpu);
194202 per_cpu(watchdog_hardlockup_touched, cpu) = false;
195203 return;
196204 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t