usb_stor_bulk_transfer_buf() waits for URB completion without a timeout. That is correct for transfers belonging to a SCSI command, whose timeout and abort handling terminate the wait, but not for transfers issued outside a SCSI command. Add a variant which takes a timeout, in jiffies; zero means no limit. usb_stor_bulk_transfer_buf() becomes a wrapper with a zero timeout, so existing callers are unchanged. Signed-off-by: Hongyu Xie --- drivers/usb/storage/transport.c | 31 ++++++++++++++++++++++++------- drivers/usb/storage/transport.h | 5 +++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 8de3015bce050..424293658918a 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -378,12 +378,17 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf, } /* - * Transfer one buffer via bulk pipe, without timeouts, but allowing early - * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe - * stalls during the transfer, the halt is automatically cleared. + * Transfer one buffer via bulk pipe, allowing early termination. Return + * codes are USB_STOR_XFER_xxx. If the bulk pipe stalls during the + * transfer, the halt is automatically cleared. + * + * A nonzero @timeout bounds the wait for URB completion, in jiffies. It + * must only be used for transfers which are not part of a SCSI command: + * those rely on the command's timeout and abort handling. */ -int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, - void *buf, unsigned int length, unsigned int *act_len) +int usb_stor_bulk_transfer_buf_timeout(struct us_data *us, unsigned int pipe, + void *buf, unsigned int length, + unsigned int *act_len, int timeout) { int result; @@ -392,14 +397,26 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, /* fill and submit the URB */ usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, usb_stor_blocking_completion, NULL); - result = usb_stor_msg_common(us, 0); + result = usb_stor_msg_common(us, timeout); /* store the actual length of the data transferred */ if (act_len) *act_len = us->current_urb->actual_length; - return interpret_urb_result(us, pipe, length, result, + return interpret_urb_result(us, pipe, length, result, us->current_urb->actual_length); } +EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf_timeout); + +/* + * Same as usb_stor_bulk_transfer_buf_timeout() with an unbounded wait. + */ +int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + void *buf, unsigned int length, + unsigned int *act_len) +{ + return usb_stor_bulk_transfer_buf_timeout(us, pipe, buf, length, + act_len, 0); +} EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf); /* diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 74ffd0d7e7b6c..361dbd77f15e3 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -77,6 +77,11 @@ extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe); extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size); +extern int usb_stor_bulk_transfer_buf_timeout(struct us_data *us, + unsigned int pipe, void *buf, + unsigned int length, + unsigned int *act_len, + int timeout); extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len); extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, -- 2.25.1