[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20090722093735.27118.36158.stgit@localhost.localdomain>
Date: Wed, 22 Jul 2009 10:39:51 +0100
From: Alan Cox <alan@...rguk.ukuu.org.uk>
To: daniel@...aq.de, linux-kernel@...r.kernel.org,
linux-usb@...r.kernel.org, stern@...land.harvard.edu
Subject: [PATCH] tty: Fix a USB serial crash/scribble
See if this one looks sensible. It does leave a tiny race window but that
semes wiser than hacking up the tty kref_put path in the middle of an -rc
series.
Thanks to Daniel and Alan Stern for chasing this down and getting traces. Also
to Daniel for being persistent when I took it as a random odd "only seen by one
user" error which it wasn't.
---
From: Alan Cox <alan@...ux.intel.com>
The port lock is used to protect the port state. However the port structure
is freed on a hangup, then the lock taken on a close. The right fix is to
drop the port on tty->shutdown() but we can't yet do that due to sleep v
non-sleeping rules. Instead do the next best thing and fix it up when we are
not in -rc season.
Reported-by: Daniel Mack <daniel@...aq.de>
Signed-off-by: Alan Cox <alan@...ux.intel.com>
---
drivers/usb/serial/usb-serial.c | 19 ++++++++++++++++++-
1 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index bd7581b..228d77c 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -340,6 +340,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
dbg("%s - port %d", __func__, port->number);
+ /* FIXME:
+ This leaves a very narrow race. Really we should do the
+ serial_do_free() on tty->shutdown(), but tty->shutdown can
+ be called from IRQ context and serial_do_free can sleep.
+
+ The right fix is probably to make the tty free (which is rare)
+ and thus tty->shutdown() occur via a work queue and simplify all
+ the drivers that use it.
+ */
+ if (tty_hung_up_p(filp)) {
+ /* serial_hangup already called serial_down at this point.
+ Another user may have already reopened the port but
+ serial_do_free is refcounted */
+ serial_do_free(port);
+ return;
+ }
if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
@@ -355,7 +371,8 @@ static void serial_hangup(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
serial_do_down(port);
tty_port_hangup(&port->port);
- serial_do_free(port);
+ /* We must not free port yet - the USB serial layer depends on it's
+ continued existence */
}
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists