aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2014-05-26 13:23:16 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-27 18:04:06 -0400
commit79eed03e77d481b55d85d1cfe5a1636a0d3897fd (patch)
tree412cc2dd0d0f05f6dbdabfff9aa333d8926c7ebf /drivers/usb/serial
parent170fad9e22df0063eba0701adb966786d7a4ec5a (diff)
USB: usb_wwan: fix urb leak at shutdown
The delayed-write queue was never emptied at shutdown (close), something which could lead to leaked urbs if the port is closed before being runtime resumed due to a write. When this happens the output buffer would not drain on close (closing_wait timeout), and after consecutive opens, writes could be corrupted with previously buffered data, transfered with reduced throughput or completely blocked. Note that unbusy_queued_urb() was simply moved out of CONFIG_PM. Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the option driver") Cc: <stable@vger.kernel.org> # v2.6.32 Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/usb_wwan.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 2b8f02696c00..2ab478b55759 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -414,12 +414,26 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
414} 414}
415EXPORT_SYMBOL(usb_wwan_open); 415EXPORT_SYMBOL(usb_wwan_open);
416 416
417static void unbusy_queued_urb(struct urb *urb,
418 struct usb_wwan_port_private *portdata)
419{
420 int i;
421
422 for (i = 0; i < N_OUT_URB; i++) {
423 if (urb == portdata->out_urbs[i]) {
424 clear_bit(i, &portdata->out_busy);
425 break;
426 }
427 }
428}
429
417void usb_wwan_close(struct usb_serial_port *port) 430void usb_wwan_close(struct usb_serial_port *port)
418{ 431{
419 int i; 432 int i;
420 struct usb_serial *serial = port->serial; 433 struct usb_serial *serial = port->serial;
421 struct usb_wwan_port_private *portdata; 434 struct usb_wwan_port_private *portdata;
422 struct usb_wwan_intf_private *intfdata = port->serial->private; 435 struct usb_wwan_intf_private *intfdata = port->serial->private;
436 struct urb *urb;
423 437
424 portdata = usb_get_serial_port_data(port); 438 portdata = usb_get_serial_port_data(port);
425 439
@@ -428,6 +442,14 @@ void usb_wwan_close(struct usb_serial_port *port)
428 portdata->opened = 0; 442 portdata->opened = 0;
429 spin_unlock_irq(&intfdata->susp_lock); 443 spin_unlock_irq(&intfdata->susp_lock);
430 444
445 for (;;) {
446 urb = usb_get_from_anchor(&portdata->delayed);
447 if (!urb)
448 break;
449 unbusy_queued_urb(urb, portdata);
450 usb_autopm_put_interface_async(serial->interface);
451 }
452
431 for (i = 0; i < N_IN_URB; i++) 453 for (i = 0; i < N_IN_URB; i++)
432 usb_kill_urb(portdata->in_urbs[i]); 454 usb_kill_urb(portdata->in_urbs[i]);
433 for (i = 0; i < N_OUT_URB; i++) 455 for (i = 0; i < N_OUT_URB; i++)
@@ -596,18 +618,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
596} 618}
597EXPORT_SYMBOL(usb_wwan_suspend); 619EXPORT_SYMBOL(usb_wwan_suspend);
598 620
599static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
600{
601 int i;
602
603 for (i = 0; i < N_OUT_URB; i++) {
604 if (urb == portdata->out_urbs[i]) {
605 clear_bit(i, &portdata->out_busy);
606 break;
607 }
608 }
609}
610
611static void play_delayed(struct usb_serial_port *port) 621static void play_delayed(struct usb_serial_port *port)
612{ 622{
613 struct usb_wwan_intf_private *data; 623 struct usb_wwan_intf_private *data;