mirror of
https://git.yoctoproject.org/meta-ti
synced 2026-07-16 22:38:04 +00:00
2177f80076
Duplicate patches between PSP and 3.2.17 have been dropped from the 3.2.17 series Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> Signed-off-by: Denys Dmytriyenko <denys@ti.com>
117 lines
4.5 KiB
Diff
117 lines
4.5 KiB
Diff
From 770feb782844457789a51d13d2933cca141bb487 Mon Sep 17 00:00:00 2001
|
|
From: Alan Stern <stern@rowland.harvard.edu>
|
|
Date: Tue, 17 Apr 2012 15:22:39 -0400
|
|
Subject: [PATCH 031/165] USB: fix deadlock in bConfigurationValue attribute
|
|
method
|
|
|
|
commit 8963c487a80b4688c9e68dcc504a90074aacc145 upstream.
|
|
|
|
This patch (as154) fixes a self-deadlock that occurs when userspace
|
|
writes to the bConfigurationValue sysfs attribute for a hub with
|
|
children. The task tries to lock the bandwidth_mutex at a time when
|
|
it already owns the lock:
|
|
|
|
The attribute's method calls usb_set_configuration(),
|
|
which calls usb_disable_device() with the bandwidth_mutex
|
|
held.
|
|
|
|
usb_disable_device() unregisters the existing interfaces,
|
|
which causes the hub driver to be unbound.
|
|
|
|
The hub_disconnect() routine calls hub_quiesce(), which
|
|
calls usb_disconnect() for each of the hub's children.
|
|
|
|
usb_disconnect() attempts to acquire the bandwidth_mutex
|
|
around a call to usb_disable_device().
|
|
|
|
The solution is to make usb_disable_device() acquire the mutex for
|
|
itself instead of requiring the caller to hold it. Then the mutex can
|
|
cover only the bandwidth deallocation operation and not the region
|
|
where the interfaces are unregistered.
|
|
|
|
This has the potential to change system behavior slightly when a
|
|
config change races with another config or altsetting change. Some of
|
|
the bandwidth released from the old config might get claimed by the
|
|
other config or altsetting, make it impossible to restore the old
|
|
config in case of a failure. But since we don't try to recover from
|
|
config-change failures anyway, this doesn't matter.
|
|
|
|
[This should be marked for stable kernels that contain the commit
|
|
fccf4e86200b8f5edd9a65da26f150e32ba79808 "USB: Free bandwidth when
|
|
usb_disable_device is called."
|
|
That commit was marked for stable kernels as old as 2.6.32.]
|
|
|
|
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
|
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
---
|
|
drivers/usb/core/hub.c | 3 ---
|
|
drivers/usb/core/message.c | 6 +++---
|
|
2 files changed, 3 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
|
index 18373ec..ab4e49f 100644
|
|
--- a/drivers/usb/core/hub.c
|
|
+++ b/drivers/usb/core/hub.c
|
|
@@ -1644,7 +1644,6 @@ void usb_disconnect(struct usb_device **pdev)
|
|
{
|
|
struct usb_device *udev = *pdev;
|
|
int i;
|
|
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
|
|
|
/* mark the device as inactive, so any further urb submissions for
|
|
* this device (and any of its children) will fail immediately.
|
|
@@ -1667,9 +1666,7 @@ void usb_disconnect(struct usb_device **pdev)
|
|
* so that the hardware is now fully quiesced.
|
|
*/
|
|
dev_dbg (&udev->dev, "unregistering device\n");
|
|
- mutex_lock(hcd->bandwidth_mutex);
|
|
usb_disable_device(udev, 0);
|
|
- mutex_unlock(hcd->bandwidth_mutex);
|
|
usb_hcd_synchronize_unlinks(udev);
|
|
|
|
usb_remove_ep_devs(&udev->ep0);
|
|
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
|
|
index aed3e07..ca717da 100644
|
|
--- a/drivers/usb/core/message.c
|
|
+++ b/drivers/usb/core/message.c
|
|
@@ -1136,8 +1136,6 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
|
|
* Deallocates hcd/hardware state for the endpoints (nuking all or most
|
|
* pending urbs) and usbcore state for the interfaces, so that usbcore
|
|
* must usb_set_configuration() before any interfaces could be used.
|
|
- *
|
|
- * Must be called with hcd->bandwidth_mutex held.
|
|
*/
|
|
void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
|
{
|
|
@@ -1190,7 +1188,9 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
|
usb_disable_endpoint(dev, i + USB_DIR_IN, false);
|
|
}
|
|
/* Remove endpoints from the host controller internal state */
|
|
+ mutex_lock(hcd->bandwidth_mutex);
|
|
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
|
+ mutex_unlock(hcd->bandwidth_mutex);
|
|
/* Second pass: remove endpoint pointers */
|
|
}
|
|
for (i = skip_ep0; i < 16; ++i) {
|
|
@@ -1750,7 +1750,6 @@ free_interfaces:
|
|
/* if it's already configured, clear out old state first.
|
|
* getting rid of old interfaces means unbinding their drivers.
|
|
*/
|
|
- mutex_lock(hcd->bandwidth_mutex);
|
|
if (dev->state != USB_STATE_ADDRESS)
|
|
usb_disable_device(dev, 1); /* Skip ep0 */
|
|
|
|
@@ -1763,6 +1762,7 @@ free_interfaces:
|
|
* host controller will not allow submissions to dropped endpoints. If
|
|
* this call fails, the device state is unchanged.
|
|
*/
|
|
+ mutex_lock(hcd->bandwidth_mutex);
|
|
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
|
if (ret < 0) {
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
--
|
|
1.7.7.6
|
|
|