From e3192ef3a63d09f369e36338ed61ad83214535cd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Jun 2014 15:02:15 -0700 Subject: [PATCH] 3.10-stable patches added patches: usb-usb_wwan-fix-urb-leak-at-shutdown.patch usb-usb_wwan-fix-write-and-suspend-race.patch --- queue-3.10/series | 2 + ...sb-usb_wwan-fix-urb-leak-at-shutdown.patch | 93 +++++++++++++++++++ ...-usb_wwan-fix-write-and-suspend-race.patch | 55 +++++++++++ 3 files changed, 150 insertions(+) create mode 100644 queue-3.10/usb-usb_wwan-fix-urb-leak-at-shutdown.patch create mode 100644 queue-3.10/usb-usb_wwan-fix-write-and-suspend-race.patch diff --git a/queue-3.10/series b/queue-3.10/series index 094447a8470..4b8bd965613 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -26,3 +26,5 @@ ext4-fix-wrong-assert-in-ext4_mb_normalize_request.patch matroxfb-perform-a-dummy-read-of-m_status.patch usb-usb_wwan-fix-urb-leak-in-write-error-path.patch usb-usb_wwan-fix-race-between-write-and-resume.patch +usb-usb_wwan-fix-write-and-suspend-race.patch +usb-usb_wwan-fix-urb-leak-at-shutdown.patch diff --git a/queue-3.10/usb-usb_wwan-fix-urb-leak-at-shutdown.patch b/queue-3.10/usb-usb_wwan-fix-urb-leak-at-shutdown.patch new file mode 100644 index 00000000000..e05325a1aa7 --- /dev/null +++ b/queue-3.10/usb-usb_wwan-fix-urb-leak-at-shutdown.patch @@ -0,0 +1,93 @@ +From 79eed03e77d481b55d85d1cfe5a1636a0d3897fd Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:16 +0200 +Subject: USB: usb_wwan: fix urb leak at shutdown + +From: Johan Hovold + +commit 79eed03e77d481b55d85d1cfe5a1636a0d3897fd upstream. + +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") + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/usb_wwan.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +--- 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 + } + EXPORT_SYMBOL(usb_wwan_open); + ++static void unbusy_queued_urb(struct urb *urb, ++ struct usb_wwan_port_private *portdata) ++{ ++ int i; ++ ++ for (i = 0; i < N_OUT_URB; i++) { ++ if (urb == portdata->out_urbs[i]) { ++ clear_bit(i, &portdata->out_busy); ++ break; ++ } ++ } ++} ++ + void usb_wwan_close(struct usb_serial_port *port) + { + int i; + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata = port->serial->private; ++ struct urb *urb; + + portdata = usb_get_serial_port_data(port); + +@@ -428,6 +442,14 @@ void usb_wwan_close(struct usb_serial_po + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); + ++ for (;;) { ++ urb = usb_get_from_anchor(&portdata->delayed); ++ if (!urb) ++ break; ++ unbusy_queued_urb(urb, portdata); ++ usb_autopm_put_interface_async(serial->interface); ++ } ++ + for (i = 0; i < N_IN_URB; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) +@@ -600,18 +622,6 @@ int usb_wwan_suspend(struct usb_serial * + } + EXPORT_SYMBOL(usb_wwan_suspend); + +-static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) +-{ +- int i; +- +- for (i = 0; i < N_OUT_URB; i++) { +- if (urb == portdata->out_urbs[i]) { +- clear_bit(i, &portdata->out_busy); +- break; +- } +- } +-} +- + static void play_delayed(struct usb_serial_port *port) + { + struct usb_wwan_intf_private *data; diff --git a/queue-3.10/usb-usb_wwan-fix-write-and-suspend-race.patch b/queue-3.10/usb-usb_wwan-fix-write-and-suspend-race.patch new file mode 100644 index 00000000000..76c9e77f447 --- /dev/null +++ b/queue-3.10/usb-usb_wwan-fix-write-and-suspend-race.patch @@ -0,0 +1,55 @@ +From 170fad9e22df0063eba0701adb966786d7a4ec5a Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:15 +0200 +Subject: USB: usb_wwan: fix write and suspend race + +From: Johan Hovold + +commit 170fad9e22df0063eba0701adb966786d7a4ec5a upstream. + +Fix race between write() and suspend() which could lead to writes being +dropped (or I/O while suspended) if the device is runtime suspended +while a write request is being processed. + +Specifically, suspend() releases the susp_lock after determining the +device is idle but before setting the suspended flag, thus leaving a +window where a concurrent write() can submit an urb. + +Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the +option driver") + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/usb_wwan.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -583,20 +583,17 @@ static void stop_read_write_urbs(struct + int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) + { + struct usb_wwan_intf_private *intfdata = serial->private; +- int b; + ++ spin_lock_irq(&intfdata->susp_lock); + if (PMSG_IS_AUTO(message)) { +- spin_lock_irq(&intfdata->susp_lock); +- b = intfdata->in_flight; +- spin_unlock_irq(&intfdata->susp_lock); +- +- if (b) ++ if (intfdata->in_flight) { ++ spin_unlock_irq(&intfdata->susp_lock); + return -EBUSY; ++ } + } +- +- spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 1; + spin_unlock_irq(&intfdata->susp_lock); ++ + stop_read_write_urbs(serial); + + return 0; -- 2.47.3