diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-10-17 00:54:27 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-06 05:53:55 +0300 |
commit | 91b32f5413c17e80ac6616dd9c62e826fa438e2d (patch) | |
tree | 89137cf0355ed9a12874bd414e4023980e69420f /drivers/tty/serial | |
parent | 64dbee31050d5b93b5fcda25508e4d3c69f6589c (diff) | |
download | linux-91b32f5413c17e80ac6616dd9c62e826fa438e2d.tar.xz |
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')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 25 |
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; } |