We need to ensure that no URBs are submitted during reset. Taking any of the mutexes can deadlock against either wdm_read or wdm_write. Define a new WDM_RESETTING flag indicating to read/write that a reset is in progress. Signed-off-by: Bjørn Mork <bjorn@xxxxxxx> --- v2: use a new dedicated flag v3: protect reset agaings wdm_open as well drivers/usb/class/cdc-wdm.c | 26 +++++++++++++++++++------- 1 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index f63601a..3673bf1 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -70,6 +70,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_POLL_RUNNING 6 #define WDM_RESPONDING 7 #define WDM_SUSPENDING 8 +#define WDM_RESETTING 9 #define WDM_MAX 16 @@ -340,6 +341,13 @@ static ssize_t wdm_write else if (test_bit(WDM_IN_USE, &desc->flags)) r = -EAGAIN; + + if (test_bit(WDM_RESETTING, &desc->flags)) { + kfree(buf); + rv = file->f_flags & O_NONBLOCK ? -EAGAIN : -EIO; + goto out; + } + if (r < 0) { kfree(buf); goto out; @@ -419,6 +427,10 @@ retry: rv = -ENODEV; goto err; } + if (test_bit(WDM_RESETTING, &desc->flags)) { + rv = -EIO; + goto err; + } usb_mark_last_busy(interface_to_usbdev(desc->intf)); if (rv < 0) { rv = -ERESTARTSYS; @@ -523,7 +535,7 @@ static int wdm_open(struct inode *inode, struct file *file) goto out; desc = usb_get_intfdata(intf); - if (test_bit(WDM_DISCONNECTING, &desc->flags)) + if (test_bit(WDM_DISCONNECTING, &desc->flags) || test_bit(WDM_RESETTING, &desc->flags)) goto out; file->private_data = desc; @@ -859,10 +871,6 @@ static int wdm_pre_reset(struct usb_interface *intf) { struct wdm_device *desc = usb_get_intfdata(intf); - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - kill_urbs(desc); - /* * we notify everybody using poll of * an exceptional situation @@ -870,9 +878,14 @@ static int wdm_pre_reset(struct usb_interface *intf) * message from the device is lost */ spin_lock_irq(&desc->iuspin); + set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */ + set_bit(WDM_READ, &desc->flags); /* unblock read */ + clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */ desc->rerr = -EINTR; spin_unlock_irq(&desc->iuspin); wake_up_all(&desc->wait); + kill_urbs(desc); + cancel_work_sync(&desc->rxwork); return 0; } @@ -881,9 +894,8 @@ static int wdm_post_reset(struct usb_interface *intf) struct wdm_device *desc = usb_get_intfdata(intf); int rv; + clear_bit(WDM_RESETTING, &desc->flags); rv = recover_from_urb_loss(desc); - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); return 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