|
|
@@ -587,10 +587,20 @@ static int wdm_flush(struct file *file, fl_owner_t id)
|
|
|
{
|
|
|
struct wdm_device *desc = file->private_data;
|
|
|
|
|
|
- wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
|
|
|
+ wait_event(desc->wait,
|
|
|
+ /*
|
|
|
+ * needs both flags. We cannot do with one
|
|
|
+ * because resetting it would cause a race
|
|
|
+ * with write() yet we need to signal
|
|
|
+ * a disconnect
|
|
|
+ */
|
|
|
+ !test_bit(WDM_IN_USE, &desc->flags) ||
|
|
|
+ test_bit(WDM_DISCONNECTING, &desc->flags));
|
|
|
|
|
|
/* cannot dereference desc->intf if WDM_DISCONNECTING */
|
|
|
- if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
|
|
|
+ if (test_bit(WDM_DISCONNECTING, &desc->flags))
|
|
|
+ return -ENODEV;
|
|
|
+ if (desc->werr < 0)
|
|
|
dev_err(&desc->intf->dev, "Error in flush path: %d\n",
|
|
|
desc->werr);
|
|
|
|
|
|
@@ -974,8 +984,6 @@ static void wdm_disconnect(struct usb_interface *intf)
|
|
|
spin_lock_irqsave(&desc->iuspin, flags);
|
|
|
set_bit(WDM_DISCONNECTING, &desc->flags);
|
|
|
set_bit(WDM_READ, &desc->flags);
|
|
|
- /* to terminate pending flushes */
|
|
|
- clear_bit(WDM_IN_USE, &desc->flags);
|
|
|
spin_unlock_irqrestore(&desc->iuspin, flags);
|
|
|
wake_up_all(&desc->wait);
|
|
|
mutex_lock(&desc->rlock);
|