summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-11-30 11:54:41 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-11 12:14:17 -0800
commitb06e48afd17b29542b04c6a8b4a7f1a7c2e446c2 (patch)
treed9bed1138b25f6b7551559ce956378921a6a7370 /drivers/usb/storage
parentaa8f612370edf2fd29ec137f7070b11d98df539b (diff)
uas: add UNLINK_DATA_URBS flag
uas_unlink_data_urbs uses this to make sure the the scsi command is not released while looking at it. This will be needed when we start calling uas_unlink_data_urbs in the request cancel code paths. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/uas.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 8b58e5e8e86..a972e53656f 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -66,6 +66,7 @@ enum {
DATA_OUT_URB_INFLIGHT = (1 << 10),
COMMAND_COMPLETED = (1 << 11),
COMMAND_ABORTED = (1 << 12),
+ UNLINK_DATA_URBS = (1 << 13),
};
/* Overrides scsi_pointer */
@@ -90,10 +91,25 @@ static LIST_HEAD(uas_work_list);
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
struct uas_cmd_info *cmdinfo)
{
+ unsigned long flags;
+
+ /*
+ * The UNLINK_DATA_URBS flag makes sure uas_try_complete
+ * (called by urb completion) doesn't release cmdinfo
+ * underneath us.
+ */
+ spin_lock_irqsave(&devinfo->lock, flags);
+ cmdinfo->state |= UNLINK_DATA_URBS;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+
if (cmdinfo->data_in_urb)
usb_unlink_urb(cmdinfo->data_in_urb);
if (cmdinfo->data_out_urb)
usb_unlink_urb(cmdinfo->data_out_urb);
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ cmdinfo->state &= ~UNLINK_DATA_URBS;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
}
static void uas_do_work(struct work_struct *work)
@@ -177,7 +193,7 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
struct uas_cmd_info *ci = (void *)&cmnd->SCp;
scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
- "%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
caller, cmnd, cmnd->request->tag,
(ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
(ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
@@ -190,7 +206,8 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
(ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "",
(ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "",
(ci->state & COMMAND_COMPLETED) ? " done" : "",
- (ci->state & COMMAND_ABORTED) ? " abort" : "");
+ (ci->state & COMMAND_ABORTED) ? " abort" : "",
+ (ci->state & UNLINK_DATA_URBS) ? " unlink": "");
}
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
@@ -201,7 +218,8 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
WARN_ON(!spin_is_locked(&devinfo->lock));
if (cmdinfo->state & (COMMAND_INFLIGHT |
DATA_IN_URB_INFLIGHT |
- DATA_OUT_URB_INFLIGHT))
+ DATA_OUT_URB_INFLIGHT |
+ UNLINK_DATA_URBS))
return -EBUSY;
BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
cmdinfo->state |= COMMAND_COMPLETED;