Skip to content

Commit 95e7249

Browse files
mikechristiemstsirkin
authored andcommitted
scsi: virtio_scsi: Add mq_poll support
This adds polling support to virtio-scsi. It's based on and works similar to virtblk support where we add a module param to specify the number of poll queues then subtract to calculate the IO queues. When using 8 poll queues and a vhost worker per queue we see 4K IOPs with fio: fio --filename=/dev/sda --direct=1 --rw=randread --bs=4k \ --ioengine=io_uring --hipri --iodepth=128 --numjobs=$NUM_JOBS increase like: jobs base poll 1 207K 296K 2 392K 552K 3 581K 860K 4 765K 1235K 5 936K 1598K 6 1104K 1880K 7 1253K 2095K 8 1311k 2187K Signed-off-by: Mike Christie <michael.christie@oracle.com> Message-Id: <20231214052649.57743-1-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 35967bd commit 95e7249

1 file changed

Lines changed: 73 additions & 5 deletions

File tree

drivers/scsi/virtio_scsi.c

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@
3737
#define VIRTIO_SCSI_EVENT_LEN 8
3838
#define VIRTIO_SCSI_VQ_BASE 2
3939

40+
static unsigned int virtscsi_poll_queues;
41+
module_param(virtscsi_poll_queues, uint, 0644);
42+
MODULE_PARM_DESC(virtscsi_poll_queues,
43+
"The number of dedicated virtqueues for polling I/O");
44+
4045
/* Command queue element */
4146
struct virtio_scsi_cmd {
4247
struct scsi_cmnd *sc;
@@ -76,6 +81,7 @@ struct virtio_scsi {
7681
struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];
7782

7883
u32 num_queues;
84+
int io_queues[HCTX_MAX_TYPES];
7985

8086
struct hlist_node node;
8187

@@ -722,9 +728,49 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
722728
static void virtscsi_map_queues(struct Scsi_Host *shost)
723729
{
724730
struct virtio_scsi *vscsi = shost_priv(shost);
725-
struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
731+
int i, qoff;
732+
733+
for (i = 0, qoff = 0; i < shost->nr_maps; i++) {
734+
struct blk_mq_queue_map *map = &shost->tag_set.map[i];
735+
736+
map->nr_queues = vscsi->io_queues[i];
737+
map->queue_offset = qoff;
738+
qoff += map->nr_queues;
739+
740+
if (map->nr_queues == 0)
741+
continue;
742+
743+
/*
744+
* Regular queues have interrupts and hence CPU affinity is
745+
* defined by the core virtio code, but polling queues have
746+
* no interrupts so we let the block layer assign CPU affinity.
747+
*/
748+
if (i == HCTX_TYPE_POLL)
749+
blk_mq_map_queues(map);
750+
else
751+
blk_mq_virtio_map_queues(map, vscsi->vdev, 2);
752+
}
753+
}
754+
755+
static int virtscsi_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
756+
{
757+
struct virtio_scsi *vscsi = shost_priv(shost);
758+
struct virtio_scsi_vq *virtscsi_vq = &vscsi->req_vqs[queue_num];
759+
unsigned long flags;
760+
unsigned int len;
761+
int found = 0;
762+
void *buf;
763+
764+
spin_lock_irqsave(&virtscsi_vq->vq_lock, flags);
765+
766+
while ((buf = virtqueue_get_buf(virtscsi_vq->vq, &len)) != NULL) {
767+
virtscsi_complete_cmd(vscsi, buf);
768+
found++;
769+
}
770+
771+
spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
726772

727-
blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
773+
return found;
728774
}
729775

730776
static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
@@ -751,6 +797,7 @@ static const struct scsi_host_template virtscsi_host_template = {
751797
.this_id = -1,
752798
.cmd_size = sizeof(struct virtio_scsi_cmd),
753799
.queuecommand = virtscsi_queuecommand,
800+
.mq_poll = virtscsi_mq_poll,
754801
.commit_rqs = virtscsi_commit_rqs,
755802
.change_queue_depth = virtscsi_change_queue_depth,
756803
.eh_abort_handler = virtscsi_abort,
@@ -795,13 +842,14 @@ static int virtscsi_init(struct virtio_device *vdev,
795842
{
796843
int err;
797844
u32 i;
798-
u32 num_vqs;
845+
u32 num_vqs, num_poll_vqs, num_req_vqs;
799846
vq_callback_t **callbacks;
800847
const char **names;
801848
struct virtqueue **vqs;
802849
struct irq_affinity desc = { .pre_vectors = 2 };
803850

804-
num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE;
851+
num_req_vqs = vscsi->num_queues;
852+
num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE;
805853
vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL);
806854
callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *),
807855
GFP_KERNEL);
@@ -812,15 +860,31 @@ static int virtscsi_init(struct virtio_device *vdev,
812860
goto out;
813861
}
814862

863+
num_poll_vqs = min_t(unsigned int, virtscsi_poll_queues,
864+
num_req_vqs - 1);
865+
vscsi->io_queues[HCTX_TYPE_DEFAULT] = num_req_vqs - num_poll_vqs;
866+
vscsi->io_queues[HCTX_TYPE_READ] = 0;
867+
vscsi->io_queues[HCTX_TYPE_POLL] = num_poll_vqs;
868+
869+
dev_info(&vdev->dev, "%d/%d/%d default/read/poll queues\n",
870+
vscsi->io_queues[HCTX_TYPE_DEFAULT],
871+
vscsi->io_queues[HCTX_TYPE_READ],
872+
vscsi->io_queues[HCTX_TYPE_POLL]);
873+
815874
callbacks[0] = virtscsi_ctrl_done;
816875
callbacks[1] = virtscsi_event_done;
817876
names[0] = "control";
818877
names[1] = "event";
819-
for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs; i++) {
878+
for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs - num_poll_vqs; i++) {
820879
callbacks[i] = virtscsi_req_done;
821880
names[i] = "request";
822881
}
823882

883+
for (; i < num_vqs; i++) {
884+
callbacks[i] = NULL;
885+
names[i] = "request_poll";
886+
}
887+
824888
/* Discover virtqueues and write information to configuration. */
825889
err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
826890
if (err)
@@ -874,6 +938,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
874938

875939
sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
876940
shost->sg_tablesize = sg_elems;
941+
shost->nr_maps = 1;
877942
vscsi = shost_priv(shost);
878943
vscsi->vdev = vdev;
879944
vscsi->num_queues = num_queues;
@@ -883,6 +948,9 @@ static int virtscsi_probe(struct virtio_device *vdev)
883948
if (err)
884949
goto virtscsi_init_failed;
885950

951+
if (vscsi->io_queues[HCTX_TYPE_POLL])
952+
shost->nr_maps = HCTX_TYPE_POLL + 1;
953+
886954
shost->can_queue = virtqueue_get_vring_size(vscsi->req_vqs[0].vq);
887955

888956
cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;

0 commit comments

Comments
 (0)