From stern@rowland.harvard.edu Tue Jul 24 15:23:27 2007 From: Alan Stern Date: Tue, 24 Jul 2007 18:23:23 -0400 (EDT) Subject: USB: Fix a bug in usb_start_wait_urb To: Greg KH Cc: Pavel Roskin , USB development list Message-ID: This patch (as941) fixes a bug recently added to the USB synchronous API. The status of a completed URB must be preserved separately across a completion callback. Also, the actual_length value isn't available until after the URB has fully completed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -18,9 +18,17 @@ #include "hcd.h" /* for usbcore internals */ #include "usb.h" +struct api_context { + struct completion done; + int status; +}; + static void usb_api_blocking_completion(struct urb *urb) { - complete((struct completion *)urb->context); + struct api_context *ctx = urb->context; + + ctx->status = urb->status; + complete(&ctx->done); } @@ -32,20 +40,21 @@ static void usb_api_blocking_completion( */ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) { - struct completion done; + struct api_context ctx; unsigned long expire; int retval; - int status = urb->status; - init_completion(&done); - urb->context = &done; + init_completion(&ctx.done); + urb->context = &ctx; urb->actual_length = 0; retval = usb_submit_urb(urb, GFP_NOIO); if (unlikely(retval)) goto out; expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; - if (!wait_for_completion_timeout(&done, expire)) { + if (!wait_for_completion_timeout(&ctx.done, expire)) { + usb_kill_urb(urb); + retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status); dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", @@ -54,11 +63,8 @@ static int usb_start_wait_urb(struct urb usb_pipein(urb->pipe) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); - - usb_kill_urb(urb); - retval = status == -ENOENT ? -ETIMEDOUT : status; } else - retval = status; + retval = ctx.status; out: if (actual_length) *actual_length = urb->actual_length;