Skip to content

Commit 9937a5e

Browse files
author
Jens Axboe
committed
scsi: remove performance regression due to async queue run
Commit c21e6be removed our queue request_fn re-enter protection, and defaulted to always running the queues from kblockd to be safe. This was a known potential slow down, but should be safe. Unfortunately this is causing big performance regressions for some, so we need to improve this logic. Looking into the details of the re-enter, the real issue is on requeue of requests. Requeue of requests upon seeing a BUSY condition from the device ends up re-running the queue, causing traces like this: scsi_request_fn() scsi_dispatch_cmd() scsi_queue_insert() __scsi_queue_insert() scsi_run_queue() scsi_request_fn() ... potentially causing the issue we want to avoid. So special case the requeue re-run of the queue, but improve it to offload the entire run of local queue and starved queue from a single workqueue callback. This is a lot better than potentially kicking off a workqueue run for each device seen. This also fixes the issue of the local device going into recursion, since the above mentioned commit never moved that queue run out of line. Signed-off-by: Jens Axboe <[email protected]>
1 parent 70087dc commit 9937a5e

File tree

3 files changed

+19
-4
lines changed

3 files changed

+19
-4
lines changed

drivers/scsi/scsi_lib.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ struct kmem_cache *scsi_sdb_cache;
7474
*/
7575
#define SCSI_QUEUE_DELAY 3
7676

77-
static void scsi_run_queue(struct request_queue *q);
78-
7977
/*
8078
* Function: scsi_unprep_request()
8179
*
@@ -161,7 +159,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
161159
blk_requeue_request(q, cmd->request);
162160
spin_unlock_irqrestore(q->queue_lock, flags);
163161

164-
scsi_run_queue(q);
162+
kblockd_schedule_work(q, &device->requeue_work);
165163

166164
return 0;
167165
}
@@ -433,7 +431,11 @@ static void scsi_run_queue(struct request_queue *q)
433431
continue;
434432
}
435433

436-
blk_run_queue_async(sdev->request_queue);
434+
spin_unlock(shost->host_lock);
435+
spin_lock(sdev->request_queue->queue_lock);
436+
__blk_run_queue(sdev->request_queue);
437+
spin_unlock(sdev->request_queue->queue_lock);
438+
spin_lock(shost->host_lock);
437439
}
438440
/* put any unprocessed entries back */
439441
list_splice(&starved_list, &shost->starved_list);
@@ -442,6 +444,16 @@ static void scsi_run_queue(struct request_queue *q)
442444
blk_run_queue(q);
443445
}
444446

447+
void scsi_requeue_run_queue(struct work_struct *work)
448+
{
449+
struct scsi_device *sdev;
450+
struct request_queue *q;
451+
452+
sdev = container_of(work, struct scsi_device, requeue_work);
453+
q = sdev->request_queue;
454+
scsi_run_queue(q);
455+
}
456+
445457
/*
446458
* Function: scsi_requeue_command()
447459
*

drivers/scsi/scsi_scan.c

+2
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
242242
int display_failure_msg = 1, ret;
243243
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
244244
extern void scsi_evt_thread(struct work_struct *work);
245+
extern void scsi_requeue_run_queue(struct work_struct *work);
245246

246247
sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
247248
GFP_ATOMIC);
@@ -264,6 +265,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
264265
INIT_LIST_HEAD(&sdev->event_list);
265266
spin_lock_init(&sdev->list_lock);
266267
INIT_WORK(&sdev->event_work, scsi_evt_thread);
268+
INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
267269

268270
sdev->sdev_gendev.parent = get_device(&starget->dev);
269271
sdev->sdev_target = starget;

include/scsi/scsi_device.h

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ struct scsi_device {
169169
sdev_dev;
170170

171171
struct execute_work ew; /* used to get process context on put */
172+
struct work_struct requeue_work;
172173

173174
struct scsi_dh_data *scsi_dh_data;
174175
enum scsi_device_state sdev_state;

0 commit comments

Comments
 (0)