]> git.itanic.dy.fi Git - linux-stable/commitdiff
dump_stack: Do not get cpu_sync for panic CPU
authorJohn Ogness <john.ogness@linutronix.de>
Wed, 7 Feb 2024 13:41:03 +0000 (14:47 +0106)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 13 Apr 2024 11:09:58 +0000 (13:09 +0200)
[ Upstream commit 7412dc6d55eed6b76180e40ac3601412ebde29bd ]

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: Sasha Levin <sashal@kernel.org>
include/linux/printk.h
kernel/printk/internal.h
lib/dump_stack.c

index 8ef499ab3c1ed2ec98946c9fd55329f876e47295..955e31860095ed01b511d52e43b1f9211c6dec69 100644 (file)
@@ -273,6 +273,8 @@ static inline void printk_trigger_flush(void)
 }
 #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 ac2d9750e5f81719fac01e093a92bbcc4cef1571..6c2afee5ef6204b5ce4483505e5e8c2034874bc7 100644 (file)
@@ -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 83471e81501a7249306ef62e173c4dce7960adc7..222c6d6c8281a421b1a58f49b5e11e5048dce784 100644 (file)
@@ -96,15 +96,25 @@ static void __dump_stack(const char *log_lvl)
  */
 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);