From: John Ogness <john.ogness@linutronix.de> Date: Wed, 7 Feb 2024 14:47:03 +0106 Subject: [PATCH 05/48] dump_stack: Do not get cpu_sync for panic CPU dump_stack() is called in panic(). If for some reason another CPU is holding the printk_cpu_sync and is unable to release it, the panic CPU will be unable to continue and print the stacktrace. Since non-panic CPUs are not allowed to store new printk messages anyway, there is no need to synchronize the stacktrace output in a panic situation. For the panic CPU, do not get the printk_cpu_sync because it is not needed and avoids a potential deadlock scenario in panic(). Link: https://lore.kernel.org/lkml/ZcIGKU8sxti38Kok@alley Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20240207134103.1357162-15-john.ogness@linutronix.de Signed-off-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- include/linux/printk.h | 2 ++ kernel/printk/internal.h | 1 - lib/dump_stack.c | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) Index: linux-6.8.2-rt10/include/linux/printk.h =================================================================== @ linux-6.8.2-rt10/include/linux/printk.h:276 @ static inline void printk_trigger_flush( } #endif +bool this_cpu_in_panic(void); + #ifdef CONFIG_SMP extern int __printk_cpu_sync_try_get(void); extern void __printk_cpu_sync_wait(void); Index: linux-6.8.2-rt10/kernel/printk/internal.h =================================================================== --- linux-6.8.2-rt10.orig/kernel/printk/internal.h +++ linux-6.8.2-rt10/kernel/printk/internal.h @ linux-6.8.2-rt10/include/linux/printk.h:133 @ struct printk_message { }; bool other_cpu_in_panic(void); -bool this_cpu_in_panic(void); bool printk_get_next_message(struct printk_message *pmsg, u64 seq, bool is_extended, bool may_supress); Index: linux-6.8.2-rt10/lib/dump_stack.c =================================================================== --- linux-6.8.2-rt10.orig/lib/dump_stack.c +++ linux-6.8.2-rt10/lib/dump_stack.c @ linux-6.8.2-rt10/include/linux/printk.h:99 @ static void __dump_stack(const char *log */ asmlinkage __visible void dump_stack_lvl(const char *log_lvl) { + bool in_panic = this_cpu_in_panic(); unsigned long flags; /* * Permit this cpu to perform nested stack dumps while serialising - * against other CPUs + * against other CPUs, unless this CPU is in panic. + * + * When in panic, non-panic CPUs are not permitted to store new + * printk messages so there is no need to synchronize the output. + * This avoids potential deadlock in panic() if another CPU is + * holding and unable to release the printk_cpu_sync. */ - printk_cpu_sync_get_irqsave(flags); + if (!in_panic) + printk_cpu_sync_get_irqsave(flags); + __dump_stack(log_lvl); - printk_cpu_sync_put_irqrestore(flags); + + if (!in_panic) + printk_cpu_sync_put_irqrestore(flags); } EXPORT_SYMBOL(dump_stack_lvl);