diff options
author | Hans de Goede <hdegoede@redhat.com> | 2014-09-13 06:26:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 00:42:11 -0400 |
commit | 4c5481efb4346948ba7034432f86235a16ac9180 (patch) | |
tree | bacb19c8689964e38d98f7e6878b7dfbca7a667e /drivers/usb | |
parent | 616f0e6cab4698309ff9e48ee2a85b5eb78cf31a (diff) |
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: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/storage/uas.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index b1a1acb43461..10a3dea041ed 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c | |||
@@ -249,6 +249,25 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller) | |||
249 | (ci->state & IS_IN_WORK_LIST) ? " work" : ""); | 249 | (ci->state & IS_IN_WORK_LIST) ? " work" : ""); |
250 | } | 250 | } |
251 | 251 | ||
252 | static void uas_free_unsubmitted_urbs(struct scsi_cmnd *cmnd) | ||
253 | { | ||
254 | struct uas_cmd_info *cmdinfo; | ||
255 | |||
256 | if (!cmnd) | ||
257 | return; | ||
258 | |||
259 | cmdinfo = (void *)&cmnd->SCp; | ||
260 | |||
261 | if (cmdinfo->state & SUBMIT_CMD_URB) | ||
262 | usb_free_urb(cmdinfo->cmd_urb); | ||
263 | |||
264 | /* data urbs may have never gotten their submit flag set */ | ||
265 | if (!(cmdinfo->state & DATA_IN_URB_INFLIGHT)) | ||
266 | usb_free_urb(cmdinfo->data_in_urb); | ||
267 | if (!(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) | ||
268 | usb_free_urb(cmdinfo->data_out_urb); | ||
269 | } | ||
270 | |||
252 | static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) | 271 | static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) |
253 | { | 272 | { |
254 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | 273 | 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 | WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED); | 282 | WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED); |
264 | cmdinfo->state |= COMMAND_COMPLETED; | 283 | cmdinfo->state |= COMMAND_COMPLETED; |
265 | devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; | 284 | devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; |
285 | uas_free_unsubmitted_urbs(cmnd); | ||
266 | cmnd->scsi_done(cmnd); | 286 | cmnd->scsi_done(cmnd); |
267 | return 0; | 287 | return 0; |
268 | } | 288 | } |
@@ -738,6 +758,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) | |||
738 | if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) | 758 | if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) |
739 | data_out_urb = usb_get_urb(cmdinfo->data_out_urb); | 759 | data_out_urb = usb_get_urb(cmdinfo->data_out_urb); |
740 | 760 | ||
761 | uas_free_unsubmitted_urbs(cmnd); | ||
762 | |||
741 | spin_unlock_irqrestore(&devinfo->lock, flags); | 763 | spin_unlock_irqrestore(&devinfo->lock, flags); |
742 | 764 | ||
743 | if (data_in_urb) { | 765 | if (data_in_urb) { |