]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - kernel/printk/printk.c
printk: Disable passing console lock owner completely during panic()
[thirdparty/linux.git] / kernel / printk / printk.c
index f3a7f5a6f6f87182a803731f4f4ed23e4a840bb0..cb99c854a648168e7011a9e995c6b7476787035f 100644 (file)
@@ -1869,10 +1869,23 @@ static bool console_waiter;
  */
 static void console_lock_spinning_enable(void)
 {
+       /*
+        * Do not use spinning in panic(). The panic CPU wants to keep the lock.
+        * Non-panic CPUs abandon the flush anyway.
+        *
+        * Just keep the lockdep annotation. The panic-CPU should avoid
+        * taking console_owner_lock because it might cause a deadlock.
+        * This looks like the easiest way how to prevent false lockdep
+        * reports without handling races a lockless way.
+        */
+       if (panic_in_progress())
+               goto lockdep;
+
        raw_spin_lock(&console_owner_lock);
        console_owner = current;
        raw_spin_unlock(&console_owner_lock);
 
+lockdep:
        /* The waiter may spin on us after setting console_owner */
        spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_);
 }
@@ -1897,6 +1910,22 @@ static int console_lock_spinning_disable_and_check(int cookie)
 {
        int waiter;
 
+       /*
+        * Ignore spinning waiters during panic() because they might get stopped
+        * or blocked at any time,
+        *
+        * It is safe because nobody is allowed to start spinning during panic
+        * in the first place. If there has been a waiter then non panic CPUs
+        * might stay spinning. They would get stopped anyway. The panic context
+        * will never start spinning and an interrupted spin on panic CPU will
+        * never continue.
+        */
+       if (panic_in_progress()) {
+               /* Keep lockdep happy. */
+               spin_release(&console_owner_dep_map, _THIS_IP_);
+               return 0;
+       }
+
        raw_spin_lock(&console_owner_lock);
        waiter = READ_ONCE(console_waiter);
        console_owner = NULL;