Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/watchdog: help remote CPUs to flush NMI printk output

The printk layer at the moment does not seem to have a good way to force
flush printk messages that are created in NMI context, except in the
panic path.

NMI-context printk messages normally get to the console with irq_work,
but that won't help if the CPU is stuck with irqs disabled, as can be
the case for hard lockup watchdog messages.

The watchdog currently flushes the printk buffers after detecting a
lockup on remote CPUs, but they may not have processed their NMI IPI
yet by that stage, or they may have self-detected a lockup in which
case they won't go via this NMI IPI path.

Improve the situation by having NMI-context mark a flag if it called
printk, and have watchdog timer interrupts check if that flag was set
and try to flush if it was. Latency is not a big problem because we
were already stuck for a while, just need to try to make sure the
messages eventually make it out.

Depends-on: 5d5e4522a7f4 ("printk: restore flushing of NMI buffers on remote CPUs after NMI backtraces")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Laurent Dufour <ldufour@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20211119113146.752759-6-npiggin@gmail.com

authored by

Nicholas Piggin and committed by
Michael Ellerman
e012c499 57dd3a7b

+31 -6
+31 -6
arch/powerpc/kernel/watchdog.c
··· 86 86 /* SMP checker bits */ 87 87 static unsigned long __wd_smp_lock; 88 88 static unsigned long __wd_reporting; 89 + static unsigned long __wd_nmi_output; 89 90 static cpumask_t wd_smp_cpus_pending; 90 91 static cpumask_t wd_smp_cpus_stuck; 91 92 static u64 wd_smp_last_reset_tb; ··· 154 153 show_regs(regs); 155 154 else 156 155 dump_stack(); 156 + 157 + /* 158 + * __wd_nmi_output must be set after we printk from NMI context. 159 + * 160 + * printk from NMI context defers printing to the console to irq_work. 161 + * If that NMI was taken in some code that is hard-locked, then irqs 162 + * are disabled so irq_work will never fire. That can result in the 163 + * hard lockup messages being delayed (indefinitely, until something 164 + * else kicks the console drivers). 165 + * 166 + * Setting __wd_nmi_output will cause another CPU to notice and kick 167 + * the console drivers for us. 168 + * 169 + * xchg is not needed here (it could be a smp_mb and store), but xchg 170 + * gives the memory ordering and atomicity required. 171 + */ 172 + xchg(&__wd_nmi_output, 1); 157 173 158 174 /* Do not panic from here because that can recurse into NMI IPI layer */ 159 175 } ··· 244 226 trigger_allbutself_cpu_backtrace(); 245 227 cpumask_clear(&wd_smp_cpus_ipi); 246 228 } 247 - 248 - /* 249 - * Force flush any remote buffers that might be stuck in IRQ context 250 - * and therefore could not run their irq_work. 251 - */ 252 - printk_trigger_flush(); 253 229 254 230 if (hardlockup_panic) 255 231 nmi_panic(NULL, "Hard LOCKUP"); ··· 349 337 350 338 if ((s64)(tb - wd_smp_last_reset_tb) >= (s64)wd_smp_panic_timeout_tb) 351 339 watchdog_smp_panic(cpu); 340 + 341 + if (__wd_nmi_output && xchg(&__wd_nmi_output, 0)) { 342 + /* 343 + * Something has called printk from NMI context. It might be 344 + * stuck, so this this triggers a flush that will get that 345 + * printk output to the console. 346 + * 347 + * See wd_lockup_ipi. 348 + */ 349 + printk_trigger_flush(); 350 + } 352 351 } 353 352 354 353 DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt) ··· 408 385 print_modules(); 409 386 print_irqtrace_events(current); 410 387 show_regs(regs); 388 + 389 + xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi 411 390 412 391 if (sysctl_hardlockup_all_cpu_backtrace) 413 392 trigger_allbutself_cpu_backtrace();