aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb-serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r--drivers/usb/serial/usb-serial.c28
1 files changed, 7 insertions, 21 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 21dd72a5a715..31c7a0939b98 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -316,16 +316,19 @@ static void serial_do_down(struct usb_serial_port *port)
316 * 316 *
317 * Do the resource freeing and refcount dropping for the port. We must 317 * Do the resource freeing and refcount dropping for the port. We must
318 * be careful about ordering and we must avoid freeing up the console. 318 * be careful about ordering and we must avoid freeing up the console.
319 *
320 * Called when the last tty kref is dropped.
319 */ 321 */
320 322
321static void serial_do_free(struct usb_serial_port *port) 323static void serial_do_free(struct tty_struct *tty)
322{ 324{
325 struct usb_serial_port *port = tty->driver_data;
323 struct usb_serial *serial; 326 struct usb_serial *serial;
324 struct module *owner; 327 struct module *owner;
325 328
326 /* The console is magical, do not hang up the console hardware 329 /* The console is magical, do not hang up the console hardware
327 or there will be tears */ 330 or there will be tears */
328 if (port->console) 331 if (port == NULL || port->console)
329 return; 332 return;
330 333
331 serial = port->serial; 334 serial = port->serial;
@@ -350,30 +353,12 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
350 353
351 dbg("%s - port %d", __func__, port->number); 354 dbg("%s - port %d", __func__, port->number);
352 355
353 /* FIXME:
354 This leaves a very narrow race. Really we should do the
355 serial_do_free() on tty->shutdown(), but tty->shutdown can
356 be called from IRQ context and serial_do_free can sleep.
357
358 The right fix is probably to make the tty free (which is rare)
359 and thus tty->shutdown() occur via a work queue and simplify all
360 the drivers that use it.
361 */
362 if (tty_hung_up_p(filp)) {
363 /* serial_hangup already called serial_down at this point.
364 Another user may have already reopened the port but
365 serial_do_free is refcounted */
366 serial_do_free(port);
367 return;
368 }
369
370 if (tty_port_close_start(&port->port, tty, filp) == 0) 356 if (tty_port_close_start(&port->port, tty, filp) == 0)
371 return; 357 return;
372
373 serial_do_down(port); 358 serial_do_down(port);
374 tty_port_close_end(&port->port, tty); 359 tty_port_close_end(&port->port, tty);
375 tty_port_tty_set(&port->port, NULL); 360 tty_port_tty_set(&port->port, NULL);
376 serial_do_free(port); 361
377} 362}
378 363
379static void serial_hangup(struct tty_struct *tty) 364static void serial_hangup(struct tty_struct *tty)
@@ -1243,6 +1228,7 @@ static const struct tty_operations serial_ops = {
1243 .chars_in_buffer = serial_chars_in_buffer, 1228 .chars_in_buffer = serial_chars_in_buffer,
1244 .tiocmget = serial_tiocmget, 1229 .tiocmget = serial_tiocmget,
1245 .tiocmset = serial_tiocmset, 1230 .tiocmset = serial_tiocmset,
1231 .shutdown = serial_do_free,
1246 .proc_fops = &serial_proc_fops, 1232 .proc_fops = &serial_proc_fops,
1247}; 1233};
1248 1234