Skip to content

Commit

Permalink
usb: cdc-wdm: Fix race between autosuspend and reading from the device
Browse files Browse the repository at this point in the history
While an available response is read the device must not
be autosuspended. This requires a flag dedicated to that
purpose.

Signed-off-by: Oliver Neukum <neukum@b1-systems.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Mar 19, 2010
1 parent 860e41a commit 922a5ea
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_READ 4
#define WDM_INT_STALL 5
#define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7


#define WDM_MAX 16
Expand Down Expand Up @@ -115,21 +116,22 @@ static void wdm_in_callback(struct urb *urb)
int status = urb->status;

spin_lock(&desc->iuspin);
clear_bit(WDM_RESPONDING, &desc->flags);

if (status) {
switch (status) {
case -ENOENT:
dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ENOENT");
break;
goto skip_error;
case -ECONNRESET:
dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ECONNRESET");
break;
goto skip_error;
case -ESHUTDOWN:
dev_dbg(&desc->intf->dev,
"nonzero urb status received: -ESHUTDOWN");
break;
goto skip_error;
case -EPIPE:
dev_err(&desc->intf->dev,
"nonzero urb status received: -EPIPE\n");
Expand All @@ -145,6 +147,7 @@ static void wdm_in_callback(struct urb *urb)
desc->reslength = urb->actual_length;
memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
desc->length += desc->reslength;
skip_error:
wake_up(&desc->wait);

set_bit(WDM_READ, &desc->flags);
Expand Down Expand Up @@ -227,13 +230,15 @@ static void wdm_int_callback(struct urb *urb)
desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags);
if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = usb_submit_urb(desc->response, GFP_ATOMIC);
dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
__func__, rv);
}
spin_unlock(&desc->iuspin);
if (rv < 0) {
clear_bit(WDM_RESPONDING, &desc->flags);
if (rv == -EPERM)
return;
if (rv == -ENOMEM) {
Expand Down Expand Up @@ -795,7 +800,8 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
mutex_lock(&desc->lock);
#ifdef CONFIG_PM
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;
} else {
#endif
Expand Down

0 comments on commit 922a5ea

Please sign in to comment.