]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 23 Jun 2014 19:37:09 +0000 (15:37 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 23 Jun 2014 19:37:09 +0000 (15:37 -0400)
added patches:
usb-cdc-acm-fix-broken-runtime-suspend.patch
usb-cdc-acm-fix-i-o-after-failed-open.patch
usb-cdc-acm-fix-runtime-pm-for-control-messages.patch
usb-cdc-acm-fix-runtime-pm-imbalance-at-shutdown.patch
usb-cdc-acm-fix-shutdown-and-suspend-race.patch
usb-cdc-acm-fix-write-and-resume-race.patch
usb-cdc-acm-fix-write-and-suspend-race.patch

queue-3.10/series
queue-3.10/usb-cdc-acm-fix-broken-runtime-suspend.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-i-o-after-failed-open.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-runtime-pm-for-control-messages.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-runtime-pm-imbalance-at-shutdown.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-shutdown-and-suspend-race.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-write-and-resume-race.patch [new file with mode: 0644]
queue-3.10/usb-cdc-acm-fix-write-and-suspend-race.patch [new file with mode: 0644]

index c0417aa1404348831a299347b903709c5cba65f8..6b271667b555ecfe61a752d15828787e803e2773 100644 (file)
@@ -27,3 +27,10 @@ net-mlx4_core-preserve-pci_dev_data-after-__mlx4_remove_one.patch
 kvm-lapic-sync-highest-isr-to-hardware-apic-on-eoi.patch
 arm-at91-fix-at91_sysirq_mask_rtc-for-sam9x5-socs.patch
 mips-kvm-allocate-at-least-16kb-for-exception-handlers.patch
+usb-cdc-acm-fix-write-and-suspend-race.patch
+usb-cdc-acm-fix-write-and-resume-race.patch
+usb-cdc-acm-fix-broken-runtime-suspend.patch
+usb-cdc-acm-fix-runtime-pm-for-control-messages.patch
+usb-cdc-acm-fix-shutdown-and-suspend-race.patch
+usb-cdc-acm-fix-i-o-after-failed-open.patch
+usb-cdc-acm-fix-runtime-pm-imbalance-at-shutdown.patch
diff --git a/queue-3.10/usb-cdc-acm-fix-broken-runtime-suspend.patch b/queue-3.10/usb-cdc-acm-fix-broken-runtime-suspend.patch
new file mode 100644 (file)
index 0000000..a145139
--- /dev/null
@@ -0,0 +1,125 @@
+From 140cb81ac8c625942a1d695875932c615767a526 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:38 +0200
+Subject: USB: cdc-acm: fix broken runtime suspend
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 140cb81ac8c625942a1d695875932c615767a526 upstream.
+
+The current ACM runtime-suspend implementation is broken in several
+ways:
+
+Firstly, it buffers only the first write request being made while
+suspended -- any further writes are silently dropped.
+
+Secondly, writes being dropped also leak write urbs, which are never
+reclaimed (until the device is unbound).
+
+Thirdly, even the single buffered write is not cleared at shutdown
+(which may happen before the device is resumed), something which can
+lead to another urb leak as well as a PM usage-counter leak.
+
+Fix this by implementing a delayed-write queue using urb anchors and
+making sure to discard the queue properly at shutdown.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Reported-by: Xiao Jin <jin.xiao@intel.com>
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |   32 ++++++++++++++++++++++----------
+ drivers/usb/class/cdc-acm.h |    2 +-
+ 2 files changed, 23 insertions(+), 11 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -233,12 +233,9 @@ static int acm_write_start(struct acm *a
+                                                       acm->susp_count);
+       usb_autopm_get_interface_async(acm->control);
+       if (acm->susp_count) {
+-              if (!acm->delayed_wb)
+-                      acm->delayed_wb = wb;
+-              else
+-                      usb_autopm_put_interface_async(acm->control);
++              usb_anchor_urb(wb->urb, &acm->delayed);
+               spin_unlock_irqrestore(&acm->write_lock, flags);
+-              return 0;       /* A white lie */
++              return 0;
+       }
+       usb_mark_last_busy(acm->dev);
+@@ -591,6 +588,8 @@ static void acm_port_destruct(struct tty
+ static void acm_port_shutdown(struct tty_port *port)
+ {
+       struct acm *acm = container_of(port, struct acm, port);
++      struct urb *urb;
++      struct acm_wb *wb;
+       int i;
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+@@ -599,6 +598,16 @@ static void acm_port_shutdown(struct tty
+       if (!acm->disconnected) {
+               usb_autopm_get_interface(acm->control);
+               acm_set_control(acm, acm->ctrlout = 0);
++
++              for (;;) {
++                      urb = usb_get_from_anchor(&acm->delayed);
++                      if (!urb)
++                              break;
++                      wb = urb->context;
++                      wb->use = 0;
++                      usb_autopm_put_interface_async(acm->control);
++              }
++
+               usb_kill_urb(acm->ctrlurb);
+               for (i = 0; i < ACM_NW; i++)
+                       usb_kill_urb(acm->wb[i].urb);
+@@ -1190,6 +1199,7 @@ made_compressed_probe:
+               acm->bInterval = epread->bInterval;
+       tty_port_init(&acm->port);
+       acm->port.ops = &acm_port_ops;
++      init_usb_anchor(&acm->delayed);
+       buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
+       if (!buf) {
+@@ -1459,7 +1469,7 @@ static int acm_suspend(struct usb_interf
+ static int acm_resume(struct usb_interface *intf)
+ {
+       struct acm *acm = usb_get_intfdata(intf);
+-      struct acm_wb *wb;
++      struct urb *urb;
+       int rv = 0;
+       spin_lock_irq(&acm->read_lock);
+@@ -1471,10 +1481,12 @@ static int acm_resume(struct usb_interfa
+       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
+               rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
+-              if (acm->delayed_wb) {
+-                      wb = acm->delayed_wb;
+-                      acm->delayed_wb = NULL;
+-                      acm_start_wb(acm, wb);
++              for (;;) {
++                      urb = usb_get_from_anchor(&acm->delayed);
++                      if (!urb)
++                              break;
++
++                      acm_start_wb(acm, urb->context);
+               }
+               /*
+--- a/drivers/usb/class/cdc-acm.h
++++ b/drivers/usb/class/cdc-acm.h
+@@ -117,7 +117,7 @@ struct acm {
+       unsigned int throttled:1;                       /* actually throttled */
+       unsigned int throttle_req:1;                    /* throttle requested */
+       u8 bInterval;
+-      struct acm_wb *delayed_wb;                      /* write queued for a device about to be woken */
++      struct usb_anchor delayed;                      /* writes queued for a device about to be woken */
+ };
+ #define CDC_DATA_INTERFACE_TYPE       0x0a
diff --git a/queue-3.10/usb-cdc-acm-fix-i-o-after-failed-open.patch b/queue-3.10/usb-cdc-acm-fix-i-o-after-failed-open.patch
new file mode 100644 (file)
index 0000000..c540a2d
--- /dev/null
@@ -0,0 +1,39 @@
+From e4c36076c2a6195ec62c35b03c3fde84d0087dc8 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:44 +0200
+Subject: USB: cdc-acm: fix I/O after failed open
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e4c36076c2a6195ec62c35b03c3fde84d0087dc8 upstream.
+
+Make sure to kill any already submitted read urbs on read-urb submission
+failures in open in order to prevent doing I/O for a closed port.
+
+Fixes: 088c64f81284 ("USB: cdc-acm: re-write read processing")
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -523,6 +523,7 @@ static int acm_port_activate(struct tty_
+ {
+       struct acm *acm = container_of(port, struct acm, port);
+       int retval = -ENODEV;
++      int i;
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+@@ -571,6 +572,8 @@ static int acm_port_activate(struct tty_
+       return 0;
+ error_submit_read_urbs:
++      for (i = 0; i < acm->rx_buflimit; i++)
++              usb_kill_urb(acm->read_urbs[i]);
+       acm->ctrlout = 0;
+       acm_set_control(acm, acm->ctrlout);
+ error_set_control:
diff --git a/queue-3.10/usb-cdc-acm-fix-runtime-pm-for-control-messages.patch b/queue-3.10/usb-cdc-acm-fix-runtime-pm-for-control-messages.patch
new file mode 100644 (file)
index 0000000..7ed5e16
--- /dev/null
@@ -0,0 +1,49 @@
+From bae3f4c53585e9a170da9436e0f06919874bda9a Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:39 +0200
+Subject: USB: cdc-acm: fix runtime PM for control messages
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit bae3f4c53585e9a170da9436e0f06919874bda9a upstream.
+
+Fix runtime PM handling of control messages by adding the required PM
+counter operations.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -122,13 +122,23 @@ static void acm_release_minor(struct acm
+ static int acm_ctrl_msg(struct acm *acm, int request, int value,
+                                                       void *buf, int len)
+ {
+-      int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
++      int retval;
++
++      retval = usb_autopm_get_interface(acm->control);
++      if (retval)
++              return retval;
++
++      retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
+               request, USB_RT_ACM, value,
+               acm->control->altsetting[0].desc.bInterfaceNumber,
+               buf, len, 5000);
++
+       dev_dbg(&acm->control->dev,
+                       "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
+                       __func__, request, value, len, retval);
++
++      usb_autopm_put_interface(acm->control);
++
+       return retval < 0 ? retval : 0;
+ }
diff --git a/queue-3.10/usb-cdc-acm-fix-runtime-pm-imbalance-at-shutdown.patch b/queue-3.10/usb-cdc-acm-fix-runtime-pm-imbalance-at-shutdown.patch
new file mode 100644 (file)
index 0000000..9036262
--- /dev/null
@@ -0,0 +1,52 @@
+From 5292afa657d0e790b7479ad8eef9450c1e040b3d Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:45 +0200
+Subject: USB: cdc-acm: fix runtime PM imbalance at shutdown
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 5292afa657d0e790b7479ad8eef9450c1e040b3d upstream.
+
+Make sure only to decrement the PM counters if they were actually
+incremented.
+
+Note that the USB PM counter, but not necessarily the driver core PM
+counter, is reset when the interface is unbound.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -604,12 +604,13 @@ static void acm_port_shutdown(struct tty
+       struct urb *urb;
+       struct acm_wb *wb;
+       int i;
++      int pm_err;
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+       mutex_lock(&acm->mutex);
+       if (!acm->disconnected) {
+-              usb_autopm_get_interface(acm->control);
++              pm_err = usb_autopm_get_interface(acm->control);
+               acm_set_control(acm, acm->ctrlout = 0);
+               for (;;) {
+@@ -627,7 +628,8 @@ static void acm_port_shutdown(struct tty
+               for (i = 0; i < acm->rx_buflimit; i++)
+                       usb_kill_urb(acm->read_urbs[i]);
+               acm->control->needs_remote_wakeup = 0;
+-              usb_autopm_put_interface(acm->control);
++              if (!pm_err)
++                      usb_autopm_put_interface(acm->control);
+       }
+       mutex_unlock(&acm->mutex);
+ }
diff --git a/queue-3.10/usb-cdc-acm-fix-shutdown-and-suspend-race.patch b/queue-3.10/usb-cdc-acm-fix-shutdown-and-suspend-race.patch
new file mode 100644 (file)
index 0000000..a5f6e33
--- /dev/null
@@ -0,0 +1,35 @@
+From ed797074031a37bb9bf4a70952fffc606b77274d Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:40 +0200
+Subject: USB: cdc-acm: fix shutdown and suspend race
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit ed797074031a37bb9bf4a70952fffc606b77274d upstream.
+
+We should stop I/O unconditionally at suspend rather than rely on the
+tty-port initialised flag (which is set prior to stopping I/O during
+shutdown) in order to prevent suspend returning with URBs still active.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -1470,8 +1470,7 @@ static int acm_suspend(struct usb_interf
+       if (cnt)
+               return 0;
+-      if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
+-              stop_data_traffic(acm);
++      stop_data_traffic(acm);
+       return 0;
+ }
diff --git a/queue-3.10/usb-cdc-acm-fix-write-and-resume-race.patch b/queue-3.10/usb-cdc-acm-fix-write-and-resume-race.patch
new file mode 100644 (file)
index 0000000..eb48e67
--- /dev/null
@@ -0,0 +1,79 @@
+From e144ed28bed10684f9aaec6325ed974d53f76110 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:37 +0200
+Subject: USB: cdc-acm: fix write and resume race
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e144ed28bed10684f9aaec6325ed974d53f76110 upstream.
+
+Fix race between write() and resume() due to improper locking that could
+lead to writes being reordered.
+
+Resume must be done atomically and susp_count be protected by the
+write_lock in order to prevent racing with write(). This could otherwise
+lead to writes being reordered if write() grabs the write_lock after
+susp_count is decremented, but before the delayed urb is submitted.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |   23 +++++++++--------------
+ 1 file changed, 9 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -1461,27 +1461,20 @@ static int acm_resume(struct usb_interfa
+       struct acm *acm = usb_get_intfdata(intf);
+       struct acm_wb *wb;
+       int rv = 0;
+-      int cnt;
+       spin_lock_irq(&acm->read_lock);
+-      acm->susp_count -= 1;
+-      cnt = acm->susp_count;
+-      spin_unlock_irq(&acm->read_lock);
++      spin_lock(&acm->write_lock);
+-      if (cnt)
+-              return 0;
++      if (--acm->susp_count)
++              goto out;
+       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
+-              rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
++              rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
+-              spin_lock_irq(&acm->write_lock);
+               if (acm->delayed_wb) {
+                       wb = acm->delayed_wb;
+                       acm->delayed_wb = NULL;
+-                      spin_unlock_irq(&acm->write_lock);
+                       acm_start_wb(acm, wb);
+-              } else {
+-                      spin_unlock_irq(&acm->write_lock);
+               }
+               /*
+@@ -1489,12 +1482,14 @@ static int acm_resume(struct usb_interfa
+                * do the write path at all cost
+                */
+               if (rv < 0)
+-                      goto err_out;
++                      goto out;
+-              rv = acm_submit_read_urbs(acm, GFP_NOIO);
++              rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
+       }
++out:
++      spin_unlock(&acm->write_lock);
++      spin_unlock_irq(&acm->read_lock);
+-err_out:
+       return rv;
+ }
diff --git a/queue-3.10/usb-cdc-acm-fix-write-and-suspend-race.patch b/queue-3.10/usb-cdc-acm-fix-write-and-suspend-race.patch
new file mode 100644 (file)
index 0000000..062a5e7
--- /dev/null
@@ -0,0 +1,54 @@
+From 5a345c20c17d87099224a4be12e69e5bd7023dca Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:36 +0200
+Subject: USB: cdc-acm: fix write and suspend race
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 5a345c20c17d87099224a4be12e69e5bd7023dca 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 write_lock after determining the
+device is idle but before incrementing the susp_count, thus leaving a
+window where a concurrent write() can submit an urb.
+
+Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
+that support remote wakeup")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |   15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -1434,18 +1434,15 @@ static int acm_suspend(struct usb_interf
+       struct acm *acm = usb_get_intfdata(intf);
+       int cnt;
++      spin_lock_irq(&acm->read_lock);
++      spin_lock(&acm->write_lock);
+       if (PMSG_IS_AUTO(message)) {
+-              int b;
+-
+-              spin_lock_irq(&acm->write_lock);
+-              b = acm->transmitting;
+-              spin_unlock_irq(&acm->write_lock);
+-              if (b)
++              if (acm->transmitting) {
++                      spin_unlock(&acm->write_lock);
++                      spin_unlock_irq(&acm->read_lock);
+                       return -EBUSY;
++              }
+       }
+-
+-      spin_lock_irq(&acm->read_lock);
+-      spin_lock(&acm->write_lock);
+       cnt = acm->susp_count++;
+       spin_unlock(&acm->write_lock);
+       spin_unlock_irq(&acm->read_lock);