Skip to content

Commit d285203

Browse files
author
Christoph Hellwig
committed
scsi: add support for a blk-mq based I/O path.
This patch adds support for an alternate I/O path in the scsi midlayer which uses the blk-mq infrastructure instead of the legacy request code. Use of blk-mq is fully transparent to drivers, although for now a host template field is provided to opt out of blk-mq usage in case any unforseen incompatibilities arise. In general replacing the legacy request code with blk-mq is a simple and mostly mechanical transformation. The biggest exception is the new code that deals with the fact the I/O submissions in blk-mq must happen from process context, which slightly complicates the I/O completion handler. The second biggest differences is that blk-mq is build around the concept of preallocated requests that also include driver specific data, which in SCSI context means the scsi_cmnd structure. This completely avoids dynamic memory allocations for the fast path through I/O submission. Due the preallocated requests the MQ code path exclusively uses the host-wide shared tag allocator instead of a per-LUN one. This only affects drivers actually using the block layer provided tag allocator instead of their own. Unlike the old path blk-mq always provides a tag, although drivers don't have to use it. For now the blk-mq path is disable by defauly and must be enabled using the "use_blk_mq" module parameter. Once the remaining work in the block layer to make blk-mq more suitable for slow devices is complete I hope to make it the default and eventually even remove the old code path. Based on the earlier scsi-mq prototype by Nicholas Bellinger. Thanks to Bart Van Assche and Robert Elliot for testing, benchmarking and various sugestions and code contributions. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Webb Scales <webbnh@hp.com> Acked-by: Jens Axboe <axboe@kernel.dk> Tested-by: Bart Van Assche <bvanassche@acm.org> Tested-by: Robert Elliott <elliott@hp.com>
1 parent c53c6d6 commit d285203

File tree

8 files changed

+488
-72
lines changed

8 files changed

+488
-72
lines changed

drivers/scsi/hosts.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,24 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
213213
goto fail;
214214
}
215215

216+
if (shost_use_blk_mq(shost)) {
217+
error = scsi_mq_setup_tags(shost);
218+
if (error)
219+
goto fail;
220+
}
221+
222+
/*
223+
* Note that we allocate the freelist even for the MQ case for now,
224+
* as we need a command set aside for scsi_reset_provider. Having
225+
* the full host freelist and one command available for that is a
226+
* little heavy-handed, but avoids introducing a special allocator
227+
* just for this. Eventually the structure of scsi_reset_provider
228+
* will need a major overhaul.
229+
*/
216230
error = scsi_setup_command_freelist(shost);
217231
if (error)
218-
goto fail;
232+
goto out_destroy_tags;
233+
219234

220235
if (!shost->shost_gendev.parent)
221236
shost->shost_gendev.parent = dev ? dev : &platform_bus;
@@ -226,7 +241,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
226241

227242
error = device_add(&shost->shost_gendev);
228243
if (error)
229-
goto out;
244+
goto out_destroy_freelist;
230245

231246
pm_runtime_set_active(&shost->shost_gendev);
232247
pm_runtime_enable(&shost->shost_gendev);
@@ -279,8 +294,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
279294
device_del(&shost->shost_dev);
280295
out_del_gendev:
281296
device_del(&shost->shost_gendev);
282-
out:
297+
out_destroy_freelist:
283298
scsi_destroy_command_freelist(shost);
299+
out_destroy_tags:
300+
if (shost_use_blk_mq(shost))
301+
scsi_mq_destroy_tags(shost);
284302
fail:
285303
return error;
286304
}
@@ -309,8 +327,13 @@ static void scsi_host_dev_release(struct device *dev)
309327
}
310328

311329
scsi_destroy_command_freelist(shost);
312-
if (shost->bqt)
313-
blk_free_tags(shost->bqt);
330+
if (shost_use_blk_mq(shost)) {
331+
if (shost->tag_set.tags)
332+
scsi_mq_destroy_tags(shost);
333+
} else {
334+
if (shost->bqt)
335+
blk_free_tags(shost->bqt);
336+
}
314337

315338
kfree(shost->shost_data);
316339

@@ -436,6 +459,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
436459
else
437460
shost->dma_boundary = 0xffffffff;
438461

462+
shost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq;
463+
439464
device_initialize(&shost->shost_gendev);
440465
dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
441466
shost->shost_gendev.bus = &scsi_bus_type;

drivers/scsi/scsi.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
805805
* is more IO than the LLD's can_queue (so there are not enuogh
806806
* tags) request_fn's host queue ready check will handle it.
807807
*/
808-
if (!sdev->host->bqt) {
808+
if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) {
809809
if (blk_queue_tagged(sdev->request_queue) &&
810810
blk_queue_resize_tags(sdev->request_queue, tags) != 0)
811811
goto out;
@@ -1361,6 +1361,9 @@ MODULE_LICENSE("GPL");
13611361
module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR);
13621362
MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels");
13631363

1364+
bool scsi_use_blk_mq = false;
1365+
module_param_named(use_blk_mq, scsi_use_blk_mq, bool, S_IWUSR | S_IRUGO);
1366+
13641367
static int __init init_scsi(void)
13651368
{
13661369
int error;

0 commit comments

Comments
 (0)