We're holding the global wdm_mutex through most of wdm_open, including when it calls usb_autopm_get_interface. This call can block waiting for a resume, which will need to look up the device list. So we deadlock. Fix by using a dedicated lock for the device list. Signed-off-by: Bjørn Mork <bjorn@xxxxxxx> --- v2: A spinlock makes more sense here, as pointed out by Oliver Neukum drivers/usb/class/cdc-wdm.c | 14 +++++++++----- 1 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 9f2cfb5..70197de 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -78,6 +78,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_DEFAULT_BUFSIZE 256 static DEFINE_MUTEX(wdm_mutex); +static DEFINE_SPINLOCK(wdm_device_list_lock); static LIST_HEAD(wdm_device_list); /* --- method tables --- */ @@ -124,23 +125,24 @@ static struct wdm_device *wdm_find_device(struct usb_interface *intf) { struct wdm_device *desc = NULL; - mutex_lock(&wdm_mutex); + spin_lock(&wdm_device_list_lock); list_for_each_entry(desc, &wdm_device_list, device_list) if (desc->intf == intf) break; - mutex_unlock(&wdm_mutex); + spin_unlock(&wdm_device_list_lock); return desc; } -/* caller holds wdm_mutex */ static struct wdm_device *wdm_find_device_by_minor(int minor) { struct wdm_device *desc = NULL; + spin_lock(&wdm_device_list_lock); list_for_each_entry(desc, &wdm_device_list, device_list) if (desc->intf->minor == minor) break; + spin_unlock(&wdm_device_list_lock); return desc; } @@ -304,7 +306,9 @@ static void free_urbs(struct wdm_device *desc) static void cleanup(struct wdm_device *desc) { + spin_lock(&wdm_device_list_lock); list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); kfree(desc->sbuf); kfree(desc->inbuf); kfree(desc->orq); @@ -733,9 +737,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor desc ); - mutex_lock(&wdm_mutex); + spin_lock(&wdm_device_list_lock); list_add(&desc->device_list, &wdm_device_list); - mutex_unlock(&wdm_mutex); + spin_unlock(&wdm_device_list_lock); rv = usb_register_dev(intf, &wdm_class); if (rv < 0) -- 1.7.8.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html