@@ -93,6 +93,12 @@ EXPORT_SYMBOL_GPL(console_drivers);
9393 */
9494int __read_mostly suppress_printk ;
9595
96+ /*
97+ * During panic, heavy printk by other CPUs can delay the
98+ * panic and risk deadlock on console resources.
99+ */
100+ static int __read_mostly suppress_panic_printk ;
101+
96102#ifdef CONFIG_LOCKDEP
97103static struct lockdep_map console_lock_dep_map = {
98104 .name = "console_lock"
@@ -258,6 +264,11 @@ static void __up_console_sem(unsigned long ip)
258264}
259265#define up_console_sem () __up_console_sem(_RET_IP_)
260266
267+ static bool panic_in_progress (void )
268+ {
269+ return unlikely (atomic_read (& panic_cpu ) != PANIC_CPU_INVALID );
270+ }
271+
261272/*
262273 * This is used for debugging the mess that is the VT code by
263274 * keeping track if we have the console semaphore held. It's
@@ -1844,6 +1855,16 @@ static int console_trylock_spinning(void)
18441855 if (console_trylock ())
18451856 return 1 ;
18461857
1858+ /*
1859+ * It's unsafe to spin once a panic has begun. If we are the
1860+ * panic CPU, we may have already halted the owner of the
1861+ * console_sem. If we are not the panic CPU, then we should
1862+ * avoid taking console_sem, so the panic CPU has a better
1863+ * chance of cleanly acquiring it later.
1864+ */
1865+ if (panic_in_progress ())
1866+ return 0 ;
1867+
18471868 printk_safe_enter_irqsave (flags );
18481869
18491870 raw_spin_lock (& console_owner_lock );
@@ -2219,6 +2240,10 @@ asmlinkage int vprintk_emit(int facility, int level,
22192240 if (unlikely (suppress_printk ))
22202241 return 0 ;
22212242
2243+ if (unlikely (suppress_panic_printk ) &&
2244+ atomic_read (& panic_cpu ) != raw_smp_processor_id ())
2245+ return 0 ;
2246+
22222247 if (level == LOGLEVEL_SCHED ) {
22232248 level = LOGLEVEL_DEFAULT ;
22242249 in_sched = true;
@@ -2586,6 +2611,25 @@ static int have_callable_console(void)
25862611 return 0 ;
25872612}
25882613
2614+ /*
2615+ * Return true when this CPU should unlock console_sem without pushing all
2616+ * messages to the console. This reduces the chance that the console is
2617+ * locked when the panic CPU tries to use it.
2618+ */
2619+ static bool abandon_console_lock_in_panic (void )
2620+ {
2621+ if (!panic_in_progress ())
2622+ return false;
2623+
2624+ /*
2625+ * We can use raw_smp_processor_id() here because it is impossible for
2626+ * the task to be migrated to the panic_cpu, or away from it. If
2627+ * panic_cpu has already been set, and we're not currently executing on
2628+ * that CPU, then we never will be.
2629+ */
2630+ return atomic_read (& panic_cpu ) != raw_smp_processor_id ();
2631+ }
2632+
25892633/*
25902634 * Can we actually use the console at this time on this cpu?
25912635 *
@@ -2616,6 +2660,7 @@ void console_unlock(void)
26162660{
26172661 static char ext_text [CONSOLE_EXT_LOG_MAX ];
26182662 static char text [CONSOLE_LOG_MAX ];
2663+ static int panic_console_dropped ;
26192664 unsigned long flags ;
26202665 bool do_cond_resched , retry ;
26212666 struct printk_info info ;
@@ -2670,6 +2715,10 @@ void console_unlock(void)
26702715 if (console_seq != r .info -> seq ) {
26712716 console_dropped += r .info -> seq - console_seq ;
26722717 console_seq = r .info -> seq ;
2718+ if (panic_in_progress () && panic_console_dropped ++ > 10 ) {
2719+ suppress_panic_printk = 1 ;
2720+ pr_warn_once ("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n" );
2721+ }
26732722 }
26742723
26752724 if (suppress_message_printing (r .info -> level )) {
@@ -2729,6 +2778,10 @@ void console_unlock(void)
27292778 if (handover )
27302779 return ;
27312780
2781+ /* Allow panic_cpu to take over the consoles safely */
2782+ if (abandon_console_lock_in_panic ())
2783+ break ;
2784+
27322785 if (do_cond_resched )
27332786 cond_resched ();
27342787 }
@@ -2746,7 +2799,7 @@ void console_unlock(void)
27462799 * flush, no worries.
27472800 */
27482801 retry = prb_read_valid (prb , next_seq , NULL );
2749- if (retry && console_trylock ())
2802+ if (retry && ! abandon_console_lock_in_panic () && console_trylock ())
27502803 goto again ;
27512804}
27522805EXPORT_SYMBOL (console_unlock );
0 commit comments