aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2015-01-21 14:02:43 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-06 14:53:00 -0800
commit76730c9fb39242f4f46f36ed07024deeaf29cedd (patch)
tree0621f6ad5ae974832bef0d6d140e87163f8bffe2 /include
parent482b4b71325978f4ed8af471fddfaa6325b11f80 (diff)
USB: don't cancel queued resets when unbinding drivers
commit 524134d422316a59d5464ccbc12036bbe90c5563 upstream. The USB stack provides a mechanism for drivers to request an asynchronous device reset (usb_queue_reset_device()). The mechanism uses a work item (reset_ws) embedded in the usb_interface structure used by the driver, and the reset is carried out by a work queue routine. The asynchronous reset can race with driver unbinding. When this happens, we try to cancel the queued reset before unbinding the driver, on the theory that the driver won't care about any resets once it is unbound. However, thanks to the fact that lockdep now tracks work queue accesses, this can provoke a lockdep warning in situations where the device reset causes another interface's driver to be unbound; see http://marc.info/?l=linux-usb&m=141893165203776&w=2 for an example. The reason is that the work routine for reset_ws in one interface calls cancel_queued_work() for the reset_ws in another interface. Lockdep thinks this might lead to a work routine trying to cancel itself. The simplest solution is not to cancel queued resets when unbinding drivers. This means we now need to acquire a reference to the usb_interface when queuing a reset_ws work item and to drop the reference when the work routine finishes. We also need to make sure that the usb_interface structure doesn't outlive its parent usb_device; this means acquiring and dropping a reference when the interface is created and destroyed. In addition, cancelling a queued reset can fail (if the device is in the middle of an earlier reset), and this can cause usb_reset_device() to try to rebind an interface that has been deallocated (see http://marc.info/?l=linux-usb&m=142175717016628&w=2 for details). Acquiring the extra references prevents this failure. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Russell King - ARM Linux <linux@arm.linux.org.uk> Reported-by: Olivier Sobrie <olivier@sobrie.be> Tested-by: Olivier Sobrie <olivier@sobrie.be> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/usb.h5
1 files changed, 0 insertions, 5 deletions
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 447a7e2fc19b..3827bffc11a7 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -127,10 +127,6 @@ enum usb_interface_condition {
* to the sysfs representation for that device.
* @pm_usage_cnt: PM usage counter for this interface
* @reset_ws: Used for scheduling resets from atomic context.
- * @reset_running: set to 1 if the interface is currently running a
- * queued reset so that usb_cancel_queued_reset() doesn't try to
- * remove from the workqueue when running inside the worker
- * thread. See __usb_queue_reset_device().
* @resetting_device: USB core reset the device, so use alt setting 0 as
* current; needs bandwidth alloc after reset.
*
@@ -181,7 +177,6 @@ struct usb_interface {
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
unsigned needs_binding:1; /* needs delayed unbind/rebind */
- unsigned reset_running:1;
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
struct device dev; /* interface specific device info */