[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