]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.20-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Dec 2018 08:27:41 +0000 (09:27 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Dec 2018 08:27:41 +0000 (09:27 +0100)
added patches:
panic-avoid-deadlocks-in-re-entrant-console-drivers.patch

queue-4.20/panic-avoid-deadlocks-in-re-entrant-console-drivers.patch [new file with mode: 0644]
queue-4.20/series [new file with mode: 0644]

diff --git a/queue-4.20/panic-avoid-deadlocks-in-re-entrant-console-drivers.patch b/queue-4.20/panic-avoid-deadlocks-in-re-entrant-console-drivers.patch
new file mode 100644 (file)
index 0000000..be9f5b3
--- /dev/null
@@ -0,0 +1,113 @@
+From c7c3f05e341a9a2bd1a92993d4f996cfd6e7348e Mon Sep 17 00:00:00 2001
+From: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
+Date: Thu, 25 Oct 2018 19:10:36 +0900
+Subject: panic: avoid deadlocks in re-entrant console drivers
+
+From: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
+
+commit c7c3f05e341a9a2bd1a92993d4f996cfd6e7348e upstream.
+
+From printk()/serial console point of view panic() is special, because
+it may force CPU to re-enter printk() or/and serial console driver.
+Therefore, some of serial consoles drivers are re-entrant. E.g. 8250:
+
+serial8250_console_write()
+{
+       if (port->sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
+       ...
+}
+
+panic() does set oops_in_progress via bust_spinlocks(1), so in theory
+we should be able to re-enter serial console driver from panic():
+
+       CPU0
+       <NMI>
+       uart_console_write()
+       serial8250_console_write()              // if (oops_in_progress)
+                                               //    spin_trylock_irqsave()
+       call_console_drivers()
+       console_unlock()
+       console_flush_on_panic()
+       bust_spinlocks(1)                       // oops_in_progress++
+       panic()
+       <NMI/>
+       spin_lock_irqsave(&port->lock, flags)   // spin_lock_irqsave()
+       serial8250_console_write()
+       call_console_drivers()
+       console_unlock()
+       printk()
+       ...
+
+However, this does not happen and we deadlock in serial console on
+port->lock spinlock. And the problem is that console_flush_on_panic()
+called after bust_spinlocks(0):
+
+void panic(const char *fmt, ...)
+{
+       bust_spinlocks(1);
+       ...
+       bust_spinlocks(0);
+       console_flush_on_panic();
+       ...
+}
+
+bust_spinlocks(0) decrements oops_in_progress, so oops_in_progress
+can go back to zero. Thus even re-entrant console drivers will simply
+spin on port->lock spinlock. Given that port->lock may already be
+locked either by a stopped CPU, or by the very same CPU we execute
+panic() on (for instance, NMI panic() on printing CPU) the system
+deadlocks and does not reboot.
+
+Fix this by removing bust_spinlocks(0), so oops_in_progress is always
+set in panic() now and, thus, re-entrant console drivers will trylock
+the port->lock instead of spinning on it forever, when we call them
+from console_flush_on_panic().
+
+Link: http://lkml.kernel.org/r/20181025101036.6823-1-sergey.senozhatsky@gmail.com
+Cc: Steven Rostedt <rostedt@goodmis.org>
+Cc: Daniel Wang <wonderfly@google.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
+Cc: Jiri Slaby <jslaby@suse.com>
+Cc: Peter Feiner <pfeiner@google.com>
+Cc: linux-serial@vger.kernel.org
+Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Signed-off-by: Petr Mladek <pmladek@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/panic.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/kernel/panic.c
++++ b/kernel/panic.c
+@@ -14,6 +14,7 @@
+ #include <linux/kmsg_dump.h>
+ #include <linux/kallsyms.h>
+ #include <linux/notifier.h>
++#include <linux/vt_kern.h>
+ #include <linux/module.h>
+ #include <linux/random.h>
+ #include <linux/ftrace.h>
+@@ -237,7 +238,10 @@ void panic(const char *fmt, ...)
+       if (_crash_kexec_post_notifiers)
+               __crash_kexec(NULL);
+-      bust_spinlocks(0);
++#ifdef CONFIG_VT
++      unblank_screen();
++#endif
++      console_unblank();
+       /*
+        * We may have ended up stopping the CPU holding the lock (in
diff --git a/queue-4.20/series b/queue-4.20/series
new file mode 100644 (file)
index 0000000..8a77ce7
--- /dev/null
@@ -0,0 +1 @@
+panic-avoid-deadlocks-in-re-entrant-console-drivers.patch