Commit 922a5ead authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

usb: cdc-wdm: Fix race between autosuspend and reading from the device

While an available response is read the device must not
be autosuspended. This requires a flag dedicated to that
purpose.
Signed-off-by: default avatarOliver Neukum <neukum@b1-systems.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 860e41a7
...@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); ...@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_READ 4 #define WDM_READ 4
#define WDM_INT_STALL 5 #define WDM_INT_STALL 5
#define WDM_POLL_RUNNING 6 #define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7
#define WDM_MAX 16 #define WDM_MAX 16
...@@ -115,21 +116,22 @@ static void wdm_in_callback(struct urb *urb) ...@@ -115,21 +116,22 @@ static void wdm_in_callback(struct urb *urb)
int status = urb->status; int status = urb->status;
spin_lock(&desc->iuspin); spin_lock(&desc->iuspin);
clear_bit(WDM_RESPONDING, &desc->flags);
if (status) { if (status) {
switch (status) { switch (status) {
case -ENOENT: case -ENOENT:
dev_dbg(&desc->intf->dev, dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ENOENT"); "nonzero urb status received: -ENOENT");
break; goto skip_error;
case -ECONNRESET: case -ECONNRESET:
dev_dbg(&desc->intf->dev, dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ECONNRESET"); "nonzero urb status received: -ECONNRESET");
break; goto skip_error;
case -ESHUTDOWN: case -ESHUTDOWN:
dev_dbg(&desc->intf->dev, dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ESHUTDOWN"); "nonzero urb status received: -ESHUTDOWN");
break; goto skip_error;
case -EPIPE: case -EPIPE:
dev_err(&desc->intf->dev, dev_err(&desc->intf->dev,
"nonzero urb status received: -EPIPE\n"); "nonzero urb status received: -EPIPE\n");
...@@ -145,6 +147,7 @@ static void wdm_in_callback(struct urb *urb) ...@@ -145,6 +147,7 @@ static void wdm_in_callback(struct urb *urb)
desc->reslength = urb->actual_length; desc->reslength = urb->actual_length;
memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
desc->length += desc->reslength; desc->length += desc->reslength;
skip_error:
wake_up(&desc->wait); wake_up(&desc->wait);
set_bit(WDM_READ, &desc->flags); set_bit(WDM_READ, &desc->flags);
...@@ -227,6 +230,7 @@ static void wdm_int_callback(struct urb *urb) ...@@ -227,6 +230,7 @@ static void wdm_int_callback(struct urb *urb)
desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
spin_lock(&desc->iuspin); spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags); clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags);
if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = usb_submit_urb(desc->response, GFP_ATOMIC); rv = usb_submit_urb(desc->response, GFP_ATOMIC);
dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
...@@ -234,6 +238,7 @@ static void wdm_int_callback(struct urb *urb) ...@@ -234,6 +238,7 @@ static void wdm_int_callback(struct urb *urb)
} }
spin_unlock(&desc->iuspin); spin_unlock(&desc->iuspin);
if (rv < 0) { if (rv < 0) {
clear_bit(WDM_RESPONDING, &desc->flags);
if (rv == -EPERM) if (rv == -EPERM)
return; return;
if (rv == -ENOMEM) { if (rv == -ENOMEM) {
...@@ -795,7 +800,8 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -795,7 +800,8 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
mutex_lock(&desc->lock); mutex_lock(&desc->lock);
#ifdef CONFIG_PM #ifdef CONFIG_PM
if ((message.event & PM_EVENT_AUTO) && if ((message.event & PM_EVENT_AUTO) &&
test_bit(WDM_IN_USE, &desc->flags)) { (test_bit(WDM_IN_USE, &desc->flags)
|| test_bit(WDM_RESPONDING, &desc->flags))) {
rv = -EBUSY; rv = -EBUSY;
} else { } else {
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment