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
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
-index 47ad7550c5a6..112693a4100b 100644
+---
+ drivers/usb/serial/usb_wwan.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
-@@ -660,17 +660,15 @@ int usb_wwan_resume(struct usb_serial *serial)
+@@ -731,17 +731,15 @@ int usb_wwan_resume(struct usb_serial *s
}
}
/* skip closed ports */
- spin_lock_irq(&intfdata->susp_lock);
-- if (!portdata || !portdata->opened) {
+- if (!portdata->opened) {
- spin_unlock_irq(&intfdata->susp_lock);
+ if (!portdata || !portdata->opened)
continue;
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
-@@ -683,9 +681,7 @@ int usb_wwan_resume(struct usb_serial *serial)
+@@ -754,9 +752,7 @@ int usb_wwan_resume(struct usb_serial *s
}
}
play_delayed(port);
--- /dev/null
+From 79eed03e77d481b55d85d1cfe5a1636a0d3897fd Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:16 +0200
+Subject: USB: usb_wwan: fix urb leak at shutdown
+
+From: Johan Hovold <jhovold@gmail.com>
+
+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 <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -434,12 +434,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;
+
+ dbg("%s", __func__);
+ portdata = usb_get_serial_port_data(port);
+@@ -450,6 +464,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++)
+@@ -667,18 +689,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;
--- /dev/null
+From 170fad9e22df0063eba0701adb966786d7a4ec5a Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:15 +0200
+Subject: USB: usb_wwan: fix write and suspend race
+
+From: Johan Hovold <jhovold@gmail.com>
+
+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 <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/usb_wwan.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -647,22 +647,20 @@ EXPORT_SYMBOL(usb_wwan_release);
+ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
+ {
+ struct usb_wwan_intf_private *intfdata = serial->private;
+- int b;
+
+ dbg("%s entered", __func__);
+
++ 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;