Skip to content

Commit ea9da1c

Browse files
Sarah SharpSebastian Andrzej Siewior
authored andcommitted
UAS: Re-add workqueue items if submission fails.
If the original submission (or allocation) of the URBs for a SCSI command fails, the UAS driver sticks the command structure in a workqueue and schedules uas_do_work() to run. That function removes the entire queue before walking across it and attempting to resubmit. Unfortunately, if the second submission fails, we will leak memory (because an allocated URB was not submitted) and possibly leave the SCSI command partially enqueued on some of the stream rings. Fix this by checking whether the second submission failed and re-queueing the command to the UAS workqueue and scheduling it. Signed-off-by: Sarah Sharp <[email protected]> Cc: Matthew Wilcox <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
1 parent 5611cc4 commit ea9da1c

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

drivers/usb/storage/uas.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,29 +125,38 @@ struct uas_cmd_info {
125125
/* I hate forward declarations, but I actually have a loop */
126126
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
127127
struct uas_dev_info *devinfo, gfp_t gfp);
128+
static void uas_do_work(struct work_struct *work);
128129

130+
static DECLARE_WORK(uas_work, uas_do_work);
129131
static DEFINE_SPINLOCK(uas_work_lock);
130132
static LIST_HEAD(uas_work_list);
131133

132134
static void uas_do_work(struct work_struct *work)
133135
{
134136
struct uas_cmd_info *cmdinfo;
137+
struct uas_cmd_info *temp;
135138
struct list_head list;
139+
int err;
136140

137141
spin_lock_irq(&uas_work_lock);
138142
list_replace_init(&uas_work_list, &list);
139143
spin_unlock_irq(&uas_work_lock);
140144

141-
list_for_each_entry(cmdinfo, &list, list) {
145+
list_for_each_entry_safe(cmdinfo, temp, &list, list) {
142146
struct scsi_pointer *scp = (void *)cmdinfo;
143147
struct scsi_cmnd *cmnd = container_of(scp,
144148
struct scsi_cmnd, SCp);
145-
uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
149+
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
150+
if (err) {
151+
list_del(&cmdinfo->list);
152+
spin_lock_irq(&uas_work_lock);
153+
list_add_tail(&cmdinfo->list, &uas_work_list);
154+
spin_unlock_irq(&uas_work_lock);
155+
schedule_work(&uas_work);
156+
}
146157
}
147158
}
148159

149-
static DECLARE_WORK(uas_work, uas_do_work);
150-
151160
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
152161
{
153162
struct sense_iu *sense_iu = urb->transfer_buffer;

0 commit comments

Comments
 (0)