Subject: [PATCH 05/48] dump_stack: Do not get cpu_sync for panic CPU
From: John Ogness <[email-masked]>
Date: Wed, 7 Feb 2024 14:47:03 +0106

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 <[email-masked]>
Reviewed-by: Petr Mladek <[email-masked]>
Link: https://lore.kernel.org/r/[email-masked]
Signed-off-by: Petr Mladek <[email-masked]>
Signed-off-by: Sebastian Andrzej Siewior <[email-masked]>
---
 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.orig/include/linux/printk.h
+++ linux-6.8.2-rt10/include/linux/printk.h
@@ -273,6 +273,8 @@ 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
@@ -130,7 +130,6 @@ 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
@@ -96,15 +96,25 @@ 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);