[PATCH v3] usb: cdc-wdm: cannot wait forever for blocking read/write on reset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux