serial_core: Don't re-initialize a previously initialized spinlock.
authorRandy Witt <rewitt@declaratino.com>
Thu, 17 Oct 2013 20:56:47 +0000 (16:56 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Dec 2013 00:44:21 +0000 (16:44 -0800)
The uart_set_options() code unconditionally initalizes the spinlock
on the port. This can cause a deadlock in some situations.

One instance that exposed the problem, was when writing to
/sys/module/kgdboc/parameters/kgdboc to use ttyS0 when the console
is already running on ttyS0. If the spinlock is re-initialized
while the lock is held due to output to the console, there
is a deadlock.

Assume the spinlock is initialized if the port is a console.

Signed-off-by: Randy Witt <rewitt@declaratino.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/serial_core.c

index 0f02351c9239b2221dbc3820b7896388a83a71a8..ece2049bd27016487aef8327eee7fb040ee346db 100644 (file)
@@ -1830,9 +1830,13 @@ uart_set_options(struct uart_port *port, struct console *co,
        /*
         * Ensure that the serial console lock is initialised
         * early.
+        * If this port is a console, then the spinlock is already
+        * initialised.
         */
-       spin_lock_init(&port->lock);
-       lockdep_set_class(&port->lock, &port_lock_key);
+       if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
+               spin_lock_init(&port->lock);
+               lockdep_set_class(&port->lock, &port_lock_key);
+       }
 
        memset(&termios, 0, sizeof(struct ktermios));