Skip to content

Commit

Permalink
scsi: add support for a blk-mq based I/O path.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Martin K. Petersen <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Reviewed-by: Webb Scales <[email protected]>
Acked-by: Jens Axboe <[email protected]>
Tested-by: Bart Van Assche <[email protected]>
Tested-by: Robert Elliott <[email protected]>
  • Loading branch information
Christoph Hellwig committed Jul 25, 2014
1 parent c53c6d6 commit d285203
Show file tree
Hide file tree
Showing 8 changed files with 488 additions and 72 deletions.
35 changes: 30 additions & 5 deletions drivers/scsi/hosts.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,24 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
goto fail;
}

if (shost_use_blk_mq(shost)) {
error = scsi_mq_setup_tags(shost);
if (error)
goto fail;
}

/*
* Note that we allocate the freelist even for the MQ case for now,
* as we need a command set aside for scsi_reset_provider. Having
* the full host freelist and one command available for that is a
* little heavy-handed, but avoids introducing a special allocator
* just for this. Eventually the structure of scsi_reset_provider
* will need a major overhaul.
*/
error = scsi_setup_command_freelist(shost);
if (error)
goto fail;
goto out_destroy_tags;


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

error = device_add(&shost->shost_gendev);
if (error)
goto out;
goto out_destroy_freelist;

pm_runtime_set_active(&shost->shost_gendev);
pm_runtime_enable(&shost->shost_gendev);
Expand Down Expand Up @@ -279,8 +294,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
device_del(&shost->shost_dev);
out_del_gendev:
device_del(&shost->shost_gendev);
out:
out_destroy_freelist:
scsi_destroy_command_freelist(shost);
out_destroy_tags:
if (shost_use_blk_mq(shost))
scsi_mq_destroy_tags(shost);
fail:
return error;
}
Expand Down Expand Up @@ -309,8 +327,13 @@ static void scsi_host_dev_release(struct device *dev)
}

scsi_destroy_command_freelist(shost);
if (shost->bqt)
blk_free_tags(shost->bqt);
if (shost_use_blk_mq(shost)) {
if (shost->tag_set.tags)
scsi_mq_destroy_tags(shost);
} else {
if (shost->bqt)
blk_free_tags(shost->bqt);
}

kfree(shost->shost_data);

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

shost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq;

device_initialize(&shost->shost_gendev);
dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
shost->shost_gendev.bus = &scsi_bus_type;
Expand Down
5 changes: 4 additions & 1 deletion drivers/scsi/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
* is more IO than the LLD's can_queue (so there are not enuogh
* tags) request_fn's host queue ready check will handle it.
*/
if (!sdev->host->bqt) {
if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) {
if (blk_queue_tagged(sdev->request_queue) &&
blk_queue_resize_tags(sdev->request_queue, tags) != 0)
goto out;
Expand Down Expand Up @@ -1361,6 +1361,9 @@ MODULE_LICENSE("GPL");
module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels");

bool scsi_use_blk_mq = false;
module_param_named(use_blk_mq, scsi_use_blk_mq, bool, S_IWUSR | S_IRUGO);

static int __init init_scsi(void)
{
int error;
Expand Down
Loading

0 comments on commit d285203

Please sign in to comment.