Commit 4c5481ef authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

uas: Fix memleak of non-submitted urbs

Not all urbs we've allocated are necessarily also submitted, non-submitted
urbs will not be free-ed by their completion handler. So we need to free
them manually.

There are 2 scenarios where this can happen:

1) We have failed to submit some urbs at abort / disconnect
2) When running over usb-2 we may have never tried to submit the data urbs
   when completing the scsi cmnd, because we never got a READ/WRITE_READY iu
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 616f0e6c
...@@ -249,6 +249,25 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller) ...@@ -249,6 +249,25 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
(ci->state & IS_IN_WORK_LIST) ? " work" : ""); (ci->state & IS_IN_WORK_LIST) ? " work" : "");
} }
static void uas_free_unsubmitted_urbs(struct scsi_cmnd *cmnd)
{
struct uas_cmd_info *cmdinfo;
if (!cmnd)
return;
cmdinfo = (void *)&cmnd->SCp;
if (cmdinfo->state & SUBMIT_CMD_URB)
usb_free_urb(cmdinfo->cmd_urb);
/* data urbs may have never gotten their submit flag set */
if (!(cmdinfo->state & DATA_IN_URB_INFLIGHT))
usb_free_urb(cmdinfo->data_in_urb);
if (!(cmdinfo->state & DATA_OUT_URB_INFLIGHT))
usb_free_urb(cmdinfo->data_out_urb);
}
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
{ {
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
...@@ -263,6 +282,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) ...@@ -263,6 +282,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED); WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
cmdinfo->state |= COMMAND_COMPLETED; cmdinfo->state |= COMMAND_COMPLETED;
devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL;
uas_free_unsubmitted_urbs(cmnd);
cmnd->scsi_done(cmnd); cmnd->scsi_done(cmnd);
return 0; return 0;
} }
...@@ -738,6 +758,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) ...@@ -738,6 +758,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
data_out_urb = usb_get_urb(cmdinfo->data_out_urb); data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
uas_free_unsubmitted_urbs(cmnd);
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
if (data_in_urb) { if (data_in_urb) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment