]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2014 22:02:15 +0000 (15:02 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2014 22:02:15 +0000 (15:02 -0700)
added patches:
usb-usb_wwan-fix-urb-leak-at-shutdown.patch
usb-usb_wwan-fix-write-and-suspend-race.patch

queue-3.10/series
queue-3.10/usb-usb_wwan-fix-urb-leak-at-shutdown.patch [new file with mode: 0644]
queue-3.10/usb-usb_wwan-fix-write-and-suspend-race.patch [new file with mode: 0644]

index 094447a84700bfdfd001eec9b04ae46f4893b6bc..4b8bd965613de373e981c2b7de83ab830402c6e4 100644 (file)
@@ -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 (file)
index 0000000..e05325a
--- /dev/null
@@ -0,0 +1,93 @@
+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
+@@ -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 (file)
index 0000000..76c9e77
--- /dev/null
@@ -0,0 +1,55 @@
+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 |   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;