[printk,v4,14/14] dump_stack: Do not get cpu_sync for panic CPU
Commit Message
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>
---
include/linux/printk.h | 2 ++
kernel/printk/internal.h | 1 -
lib/dump_stack.c | 16 +++++++++++++---
3 files changed, 15 insertions(+), 4 deletions(-)
Comments
On Wed 2024-02-07 14:47:03, John Ogness wrote:
> 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>
Makes sense.
Reviewed-by: Petr Mladek <pmladek@suse.com>
Best Regards,
Petr
@@ -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);
@@ -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);
@@ -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);