aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/serial_core.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-10-16 16:54:27 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-05 18:53:55 -0800
commit91b32f5413c17e80ac6616dd9c62e826fa438e2d (patch)
tree89137cf0355ed9a12874bd414e4023980e69420f /drivers/tty/serial/serial_core.c
parentserial: core: Remove extra locking in uart_write() (diff)
downloadlinux-dev-91b32f5413c17e80ac6616dd9c62e826fa438e2d.tar.xz
linux-dev-91b32f5413c17e80ac6616dd9c62e826fa438e2d.zip
serial: core: Fix port count when uart_open() errors
A port count mismatch occurs if mutex_lock_interruptible() exits uart_open() and the port has already been opened. This may prematurely close a port on an open tty. Since uart_close() is _always_ called if uart_open() fails, the port count must be corrected if errors occur. Always increment the port count in uart_open(), regardless of errors; always decrement the port count in uart_close(). Note that tty_port_close_start() decrements the port count when uart_open() was successful. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r--drivers/tty/serial/serial_core.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 0282eaaff517..3e36ecf98624 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1338,8 +1338,16 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
struct uart_port *uport;
unsigned long flags;
- if (!state)
+ if (!state) {
+ struct uart_driver *drv = tty->driver->driver_state;
+
+ state = drv->state + tty->index;
+ port = &state->port;
+ spin_lock_irq(&port->lock);
+ --port->count;
+ spin_unlock_irq(&port->lock);
return;
+ }
uport = state->uart_port;
port = &state->port;
@@ -1556,6 +1564,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
pr_debug("uart_open(%d) called\n", line);
+ spin_lock_irq(&port->lock);
+ ++port->count;
+ spin_unlock_irq(&port->lock);
+
/*
* We take the semaphore here to guarantee that we won't be re-entered
* while allocating the state structure, or while we request any IRQs
@@ -1568,17 +1580,11 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
goto end;
}
- port->count++;
if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
retval = -ENXIO;
- goto err_dec_count;
+ goto err_unlock;
}
- /*
- * Once we set tty->driver_data here, we are guaranteed that
- * uart_close() will decrement the driver module use count.
- * Any failures from here onwards should not touch the count.
- */
tty->driver_data = state;
state->uart_port->state = state;
state->port.low_latency =
@@ -1599,8 +1605,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
end:
return retval;
-err_dec_count:
- port->count--;
+err_unlock:
mutex_unlock(&port->mutex);
goto end;
}