[PATCH v4 5/5] powerpc/watchdog: help remote CPUs to flush NMI printk output
Laurent Dufour
ldufour at linux.ibm.com
Sat Nov 20 02:32:54 AEDT 2021
Le 19/11/2021 à 12:31, Nicholas Piggin a écrit :
> 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.
>
> Cc: Laurent Dufour <ldufour at linux.ibm.com>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
Reviewed-by: Laurent Dufour <ldufour at linux.ibm.com>
> ---
> This patch requires commit 5d5e4522a7f4 ("printk: restore flushing of
> NMI buffers on remote CPUs after NMI backtraces"). If backporting this
> to a kernel without commit 93d102f094be ("printk: remove safe buffers"),
> then printk_safe_flush() should be used in place of
> printk_trigger_flush().
>
> Thanks,
> Nick
>
> arch/powerpc/kernel/watchdog.c | 37 ++++++++++++++++++++++++++++------
> 1 file changed, 31 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
> index 23745af38d62..bfc27496fe7e 100644
> --- a/arch/powerpc/kernel/watchdog.c
> +++ b/arch/powerpc/kernel/watchdog.c
> @@ -86,6 +86,7 @@ static DEFINE_PER_CPU(u64, wd_timer_tb);
> /* SMP checker bits */
> static unsigned long __wd_smp_lock;
> static unsigned long __wd_reporting;
> +static unsigned long __wd_nmi_output;
> static cpumask_t wd_smp_cpus_pending;
> static cpumask_t wd_smp_cpus_stuck;
> static u64 wd_smp_last_reset_tb;
> @@ -154,6 +155,23 @@ static void wd_lockup_ipi(struct pt_regs *regs)
> else
> dump_stack();
>
> + /*
> + * __wd_nmi_output must be set after we printk from NMI context.
> + *
> + * printk from NMI context defers printing to the console to irq_work.
> + * If that NMI was taken in some code that is hard-locked, then irqs
> + * are disabled so irq_work will never fire. That can result in the
> + * hard lockup messages being delayed (indefinitely, until something
> + * else kicks the console drivers).
> + *
> + * Setting __wd_nmi_output will cause another CPU to notice and kick
> + * the console drivers for us.
> + *
> + * xchg is not needed here (it could be a smp_mb and store), but xchg
> + * gives the memory ordering and atomicity required.
> + */
> + xchg(&__wd_nmi_output, 1);
> +
> /* Do not panic from here because that can recurse into NMI IPI layer */
> }
>
> @@ -227,12 +245,6 @@ static void watchdog_smp_panic(int cpu)
> cpumask_clear(&wd_smp_cpus_ipi);
> }
>
> - /*
> - * Force flush any remote buffers that might be stuck in IRQ context
> - * and therefore could not run their irq_work.
> - */
> - printk_trigger_flush();
> -
> if (hardlockup_panic)
> nmi_panic(NULL, "Hard LOCKUP");
>
> @@ -337,6 +349,17 @@ static void watchdog_timer_interrupt(int cpu)
>
> if ((s64)(tb - wd_smp_last_reset_tb) >= (s64)wd_smp_panic_timeout_tb)
> watchdog_smp_panic(cpu);
> +
> + if (__wd_nmi_output && xchg(&__wd_nmi_output, 0)) {
> + /*
> + * Something has called printk from NMI context. It might be
> + * stuck, so this this triggers a flush that will get that
> + * printk output to the console.
> + *
> + * See wd_lockup_ipi.
> + */
> + printk_trigger_flush();
> + }
> }
>
> DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
> @@ -386,6 +409,8 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
> print_irqtrace_events(current);
> show_regs(regs);
>
> + xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi
> +
> if (sysctl_hardlockup_all_cpu_backtrace)
> trigger_allbutself_cpu_backtrace();
>
>
More information about the Linuxppc-dev
mailing list