printk: Drop console_sem during panic
authorStephen Brennan <stephen.s.brennan@oracle.com>
Wed, 2 Feb 2022 17:18:21 +0000 (09:18 -0800)
committerPetr Mladek <pmladek@suse.com>
Mon, 14 Feb 2022 12:39:20 +0000 (13:39 +0100)
If another CPU is in panic, we are about to be halted. Try to gracefully
abandon the console_sem, leaving it free for the panic CPU to grab.

Suggested-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20220202171821.179394-5-stephen.s.brennan@oracle.com
kernel/printk/printk.c

index 2ec6b547cda699cf9f5ea70ba4212b92b63cda96..6a51907a33b9f9c4c9e8aed527ca62fe04ca5c1a 100644 (file)
@@ -2597,6 +2597,25 @@ static int have_callable_console(void)
        return 0;
 }
 
+/*
+ * Return true when this CPU should unlock console_sem without pushing all
+ * messages to the console. This reduces the chance that the console is
+ * locked when the panic CPU tries to use it.
+ */
+static bool abandon_console_lock_in_panic(void)
+{
+       if (!panic_in_progress())
+               return false;
+
+       /*
+        * We can use raw_smp_processor_id() here because it is impossible for
+        * the task to be migrated to the panic_cpu, or away from it. If
+        * panic_cpu has already been set, and we're not currently executing on
+        * that CPU, then we never will be.
+        */
+       return atomic_read(&panic_cpu) != raw_smp_processor_id();
+}
+
 /*
  * Can we actually use the console at this time on this cpu?
  *
@@ -2745,6 +2764,10 @@ skip:
                if (handover)
                        return;
 
+               /* Allow panic_cpu to take over the consoles safely */
+               if (abandon_console_lock_in_panic())
+                       break;
+
                if (do_cond_resched)
                        cond_resched();
        }
@@ -2762,7 +2785,7 @@ skip:
         * flush, no worries.
         */
        retry = prb_read_valid(prb, next_seq, NULL);
-       if (retry && console_trylock())
+       if (retry && !abandon_console_lock_in_panic() && console_trylock())
                goto again;
 }
 EXPORT_SYMBOL(console_unlock);