From 4bd43f2c31848d751f63e8753cd2788d48fb5f30 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Jan 2009 13:44:04 +0000 Subject: tty: Fix close races in USB serial USB serial has always had races where the tty port usage count can hit zero during a receive event. The internal locking is a mutex so we can't use that in the IRQ handlers. With krefs we can tackle this differently but we still need to be careful. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/usb/serial/usb-serial.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 794b5ffe4397..aafa684a900f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -269,15 +269,19 @@ static void serial_close(struct tty_struct *tty, struct file *filp) return; } - --port->port.count; - if (port->port.count == 0) + if (port->port.count == 1) /* only call the device specific close if this - * port is being closed by the last owner */ + * port is being closed by the last owner. Ensure we do + * this before we drop the port count. The call is protected + * by the port mutex + */ port->serial->type->close(tty, port, filp); - if (port->port.count == (port->console? 1 : 0)) { + if (port->port.count == (port->console ? 2 : 1)) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { + /* We must do this before we drop the port count to + zero. */ if (tty->driver_data) tty->driver_data = NULL; tty_port_tty_set(&port->port, NULL); @@ -285,13 +289,14 @@ static void serial_close(struct tty_struct *tty, struct file *filp) } } - if (port->port.count == 0) { + if (port->port.count == 1) { mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) usb_autopm_put_interface(port->serial->interface); mutex_unlock(&port->serial->disc_mutex); module_put(port->serial->type->driver.owner); } + --port->port.count; mutex_unlock(&port->mutex); usb_serial_put(port->serial); -- cgit v1.2.2