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: Oliver Neukum <neukum@b1-systems.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
860e41a71c
commit
922a5eadd5
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue