mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-23 02:09:31 +07:00
USB: Fix a bug in usb_start_wait_urb
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 <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
a12b8db020
commit
67f5dde3d4
@ -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(struct urb *urb)
|
||||
*/
|
||||
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 *urb, int timeout, int *actual_length)
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user