aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vhost
diff options
context:
space:
mode:
authorAsias He <asias@redhat.com>2013-02-06 00:20:59 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-02-13 14:30:14 -0500
commit1b7f390eb3bfc197c979c5478eadbc2a90f07667 (patch)
tree969efecaf717e4d94b55eaaa5a3fc2f678956459 /drivers/vhost
parent67e18cf9ab21648a477e91e0d3cb6dbdb1330262 (diff)
tcm_vhost: Multi-queue support
This adds virtio-scsi multi-queue support to tcm_vhost. In order to use multi-queue, guest side multi-queue support is need. It can be found here: https://lkml.org/lkml/2012/12/18/166 Currently, only one thread is created by vhost core code for each vhost_scsi instance. Even if there are multi-queues, all the handling of guest kick (vhost_scsi_handle_kick) are processed in one thread. This is not optimal. Luckily, most of the work is offloaded to the tcm_vhost workqueue. Some initial perf numbers: 1 queue, 4 targets, 1 lun per target 4K request size, 50% randread + 50% randwrite: 127K/127k IOPS 4 queues, 4 targets, 1 lun per target 4K request size, 50% randread + 50% randwrite: 181K/181k IOPS Signed-off-by: Asias He <asias@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/vhost')
-rw-r--r--drivers/vhost/tcm_vhost.c46
-rw-r--r--drivers/vhost/tcm_vhost.h2
2 files changed, 31 insertions, 17 deletions
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
index 81ecda54b923..9951297b2427 100644
--- a/drivers/vhost/tcm_vhost.c
+++ b/drivers/vhost/tcm_vhost.c
@@ -48,6 +48,7 @@
48#include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */ 48#include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */
49#include <linux/virtio_scsi.h> 49#include <linux/virtio_scsi.h>
50#include <linux/llist.h> 50#include <linux/llist.h>
51#include <linux/bitmap.h>
51 52
52#include "vhost.c" 53#include "vhost.c"
53#include "vhost.h" 54#include "vhost.h"
@@ -59,7 +60,8 @@ enum {
59 VHOST_SCSI_VQ_IO = 2, 60 VHOST_SCSI_VQ_IO = 2,
60}; 61};
61 62
62#define VHOST_SCSI_MAX_TARGET 256 63#define VHOST_SCSI_MAX_TARGET 256
64#define VHOST_SCSI_MAX_VQ 128
63 65
64struct vhost_scsi { 66struct vhost_scsi {
65 /* Protected by vhost_scsi->dev.mutex */ 67 /* Protected by vhost_scsi->dev.mutex */
@@ -68,7 +70,7 @@ struct vhost_scsi {
68 bool vs_endpoint; 70 bool vs_endpoint;
69 71
70 struct vhost_dev dev; 72 struct vhost_dev dev;
71 struct vhost_virtqueue vqs[3]; 73 struct vhost_virtqueue vqs[VHOST_SCSI_MAX_VQ];
72 74
73 struct vhost_work vs_completion_work; /* cmd completion work item */ 75 struct vhost_work vs_completion_work; /* cmd completion work item */
74 struct llist_head vs_completion_list; /* cmd completion queue */ 76 struct llist_head vs_completion_list; /* cmd completion queue */
@@ -366,12 +368,14 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
366{ 368{
367 struct vhost_scsi *vs = container_of(work, struct vhost_scsi, 369 struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
368 vs_completion_work); 370 vs_completion_work);
371 DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
369 struct virtio_scsi_cmd_resp v_rsp; 372 struct virtio_scsi_cmd_resp v_rsp;
370 struct tcm_vhost_cmd *tv_cmd; 373 struct tcm_vhost_cmd *tv_cmd;
371 struct llist_node *llnode; 374 struct llist_node *llnode;
372 struct se_cmd *se_cmd; 375 struct se_cmd *se_cmd;
373 int ret; 376 int ret, vq;
374 377
378 bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
375 llnode = llist_del_all(&vs->vs_completion_list); 379 llnode = llist_del_all(&vs->vs_completion_list);
376 while (llnode) { 380 while (llnode) {
377 tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd, 381 tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd,
@@ -390,15 +394,20 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
390 memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf, 394 memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf,
391 v_rsp.sense_len); 395 v_rsp.sense_len);
392 ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp)); 396 ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
393 if (likely(ret == 0)) 397 if (likely(ret == 0)) {
394 vhost_add_used(&vs->vqs[2], tv_cmd->tvc_vq_desc, 0); 398 vhost_add_used(tv_cmd->tvc_vq, tv_cmd->tvc_vq_desc, 0);
395 else 399 vq = tv_cmd->tvc_vq - vs->vqs;
400 __set_bit(vq, signal);
401 } else
396 pr_err("Faulted on virtio_scsi_cmd_resp\n"); 402 pr_err("Faulted on virtio_scsi_cmd_resp\n");
397 403
398 vhost_scsi_free_cmd(tv_cmd); 404 vhost_scsi_free_cmd(tv_cmd);
399 } 405 }
400 406
401 vhost_signal(&vs->dev, &vs->vqs[2]); 407 vq = -1;
408 while ((vq = find_next_bit(signal, VHOST_SCSI_MAX_VQ, vq + 1))
409 < VHOST_SCSI_MAX_VQ)
410 vhost_signal(&vs->dev, &vs->vqs[vq]);
402} 411}
403 412
404static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( 413static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
@@ -561,9 +570,9 @@ static void tcm_vhost_submission_work(struct work_struct *work)
561 } 570 }
562} 571}
563 572
564static void vhost_scsi_handle_vq(struct vhost_scsi *vs) 573static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
574 struct vhost_virtqueue *vq)
565{ 575{
566 struct vhost_virtqueue *vq = &vs->vqs[2];
567 struct virtio_scsi_cmd_req v_req; 576 struct virtio_scsi_cmd_req v_req;
568 struct tcm_vhost_tpg *tv_tpg; 577 struct tcm_vhost_tpg *tv_tpg;
569 struct tcm_vhost_cmd *tv_cmd; 578 struct tcm_vhost_cmd *tv_cmd;
@@ -656,7 +665,7 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
656 ret = __copy_to_user(resp, &rsp, sizeof(rsp)); 665 ret = __copy_to_user(resp, &rsp, sizeof(rsp));
657 if (!ret) 666 if (!ret)
658 vhost_add_used_and_signal(&vs->dev, 667 vhost_add_used_and_signal(&vs->dev,
659 &vs->vqs[2], head, 0); 668 vq, head, 0);
660 else 669 else
661 pr_err("Faulted on virtio_scsi_cmd_resp\n"); 670 pr_err("Faulted on virtio_scsi_cmd_resp\n");
662 671
@@ -678,6 +687,7 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
678 ": %d\n", tv_cmd, exp_data_len, data_direction); 687 ": %d\n", tv_cmd, exp_data_len, data_direction);
679 688
680 tv_cmd->tvc_vhost = vs; 689 tv_cmd->tvc_vhost = vs;
690 tv_cmd->tvc_vq = vq;
681 691
682 if (unlikely(vq->iov[out].iov_len != 692 if (unlikely(vq->iov[out].iov_len !=
683 sizeof(struct virtio_scsi_cmd_resp))) { 693 sizeof(struct virtio_scsi_cmd_resp))) {
@@ -758,7 +768,7 @@ static void vhost_scsi_handle_kick(struct vhost_work *work)
758 poll.work); 768 poll.work);
759 struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev); 769 struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
760 770
761 vhost_scsi_handle_vq(vs); 771 vhost_scsi_handle_vq(vs, vq);
762} 772}
763 773
764/* 774/*
@@ -879,7 +889,7 @@ err:
879static int vhost_scsi_open(struct inode *inode, struct file *f) 889static int vhost_scsi_open(struct inode *inode, struct file *f)
880{ 890{
881 struct vhost_scsi *s; 891 struct vhost_scsi *s;
882 int r; 892 int r, i;
883 893
884 s = kzalloc(sizeof(*s), GFP_KERNEL); 894 s = kzalloc(sizeof(*s), GFP_KERNEL);
885 if (!s) 895 if (!s)
@@ -889,8 +899,9 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
889 899
890 s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick; 900 s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick;
891 s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick; 901 s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick;
892 s->vqs[VHOST_SCSI_VQ_IO].handle_kick = vhost_scsi_handle_kick; 902 for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++)
893 r = vhost_dev_init(&s->dev, s->vqs, 3); 903 s->vqs[i].handle_kick = vhost_scsi_handle_kick;
904 r = vhost_dev_init(&s->dev, s->vqs, VHOST_SCSI_MAX_VQ);
894 if (r < 0) { 905 if (r < 0) {
895 kfree(s); 906 kfree(s);
896 return r; 907 return r;
@@ -922,9 +933,10 @@ static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
922 933
923static void vhost_scsi_flush(struct vhost_scsi *vs) 934static void vhost_scsi_flush(struct vhost_scsi *vs)
924{ 935{
925 vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_CTL); 936 int i;
926 vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_EVT); 937
927 vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_IO); 938 for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
939 vhost_scsi_flush_vq(vs, i);
928} 940}
929 941
930static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) 942static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
index 519a5504d347..1d2ae7a60e11 100644
--- a/drivers/vhost/tcm_vhost.h
+++ b/drivers/vhost/tcm_vhost.h
@@ -23,6 +23,8 @@ struct tcm_vhost_cmd {
23 struct virtio_scsi_cmd_resp __user *tvc_resp; 23 struct virtio_scsi_cmd_resp __user *tvc_resp;
24 /* Pointer to vhost_scsi for our device */ 24 /* Pointer to vhost_scsi for our device */
25 struct vhost_scsi *tvc_vhost; 25 struct vhost_scsi *tvc_vhost;
26 /* Pointer to vhost_virtqueue for the cmd */
27 struct vhost_virtqueue *tvc_vq;
26 /* Pointer to vhost nexus memory */ 28 /* Pointer to vhost nexus memory */
27 struct tcm_vhost_nexus *tvc_nexus; 29 struct tcm_vhost_nexus *tvc_nexus;
28 /* The TCM I/O descriptor that is accessed via container_of() */ 30 /* The TCM I/O descriptor that is accessed via container_of() */