vhost: allow device that does not depend on vhost worker
authorJason Wang <jasowang@redhat.com>
Fri, 29 May 2020 08:02:58 +0000 (16:02 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 4 Jun 2020 19:36:51 +0000 (15:36 -0400)
vDPA device currently relays the eventfd via vhost worker. This is
inefficient due the latency of wakeup and scheduling, so this patch
tries to introduce a use_worker attribute for the vhost device. When
use_worker is not set with vhost_dev_init(), vhost won't try to
allocate a worker thread and the vhost_poll will be processed directly
in the wakeup function.

This help for vDPA since it reduces the latency caused by vhost worker.

In my testing, it saves 0.2 ms in pings between VMs on a mutual host.

Signed-off-by: Zhu Lingshan <lingshan.zhu@intel.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://lore.kernel.org/r/20200529080303.15449-2-jasowang@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/vdpa.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/vhost/vsock.c

index 2927f02cc7e1b5af56c1626973f1499c96b25244..bf5e1d81ae250652e5e74a7d6a3fdcc92c140810 100644 (file)
@@ -1326,7 +1326,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
        }
        vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX,
                       UIO_MAXIOV + VHOST_NET_BATCH,
-                      VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT,
+                      VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT, true,
                       NULL);
 
        vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, EPOLLOUT, dev);
index c39952243fd3289f23844fb9bef6c41e175a0dba..0cbaa0b3893df8afdb7bf488502a30e60e3b8315 100644 (file)
@@ -1628,7 +1628,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
                vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
        }
        vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV,
-                      VHOST_SCSI_WEIGHT, 0, NULL);
+                      VHOST_SCSI_WEIGHT, 0, true, NULL);
 
        vhost_scsi_init_inflight(vs, NULL);
 
index 0968361e3b7745906c1b7da2eab84a7bda4767bc..f22bb316b8c4f9001cf05a73f2a93610da98ea0f 100644 (file)
@@ -694,7 +694,7 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
                vqs[i] = &v->vqs[i];
                vqs[i]->handle_kick = handle_vq_kick;
        }
-       vhost_dev_init(dev, vqs, nvqs, 0, 0, 0,
+       vhost_dev_init(dev, vqs, nvqs, 0, 0, 0, false,
                       vhost_vdpa_process_iotlb_msg);
 
        dev->iotlb = vhost_iotlb_alloc(0, 0);
index 96d9871fa0cb50607914d121859c0127a3220d8a..80da9d9662f2611225b35bada6baed00da80b269 100644 (file)
@@ -166,11 +166,16 @@ static int vhost_poll_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync,
                             void *key)
 {
        struct vhost_poll *poll = container_of(wait, struct vhost_poll, wait);
+       struct vhost_work *work = &poll->work;
 
        if (!(key_to_poll(key) & poll->mask))
                return 0;
 
-       vhost_poll_queue(poll);
+       if (!poll->dev->use_worker)
+               work->fn(work);
+       else
+               vhost_poll_queue(poll);
+
        return 0;
 }
 
@@ -454,6 +459,7 @@ static size_t vhost_get_desc_size(struct vhost_virtqueue *vq,
 void vhost_dev_init(struct vhost_dev *dev,
                    struct vhost_virtqueue **vqs, int nvqs,
                    int iov_limit, int weight, int byte_weight,
+                   bool use_worker,
                    int (*msg_handler)(struct vhost_dev *dev,
                                       struct vhost_iotlb_msg *msg))
 {
@@ -471,6 +477,7 @@ void vhost_dev_init(struct vhost_dev *dev,
        dev->iov_limit = iov_limit;
        dev->weight = weight;
        dev->byte_weight = byte_weight;
+       dev->use_worker = use_worker;
        dev->msg_handler = msg_handler;
        init_llist_head(&dev->work_list);
        init_waitqueue_head(&dev->wait);
@@ -549,18 +556,21 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
        /* No owner, become one */
        dev->mm = get_task_mm(current);
        dev->kcov_handle = kcov_common_handle();
-       worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
-       if (IS_ERR(worker)) {
-               err = PTR_ERR(worker);
-               goto err_worker;
-       }
+       if (dev->use_worker) {
+               worker = kthread_create(vhost_worker, dev,
+                                       "vhost-%d", current->pid);
+               if (IS_ERR(worker)) {
+                       err = PTR_ERR(worker);
+                       goto err_worker;
+               }
 
-       dev->worker = worker;
-       wake_up_process(worker);        /* avoid contributing to loadavg */
+               dev->worker = worker;
+               wake_up_process(worker); /* avoid contributing to loadavg */
 
-       err = vhost_attach_cgroups(dev);
-       if (err)
-               goto err_cgroup;
+               err = vhost_attach_cgroups(dev);
+               if (err)
+                       goto err_cgroup;
+       }
 
        err = vhost_dev_alloc_iovecs(dev);
        if (err)
@@ -568,8 +578,10 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
 
        return 0;
 err_cgroup:
-       kthread_stop(worker);
-       dev->worker = NULL;
+       if (dev->worker) {
+               kthread_stop(dev->worker);
+               dev->worker = NULL;
+       }
 err_worker:
        if (dev->mm)
                mmput(dev->mm);
index 60cab4c782296f085ab9beb4597e2f59739a7833..c8e96a095d3b85f80023001b1dcdf793a437da57 100644 (file)
@@ -154,6 +154,7 @@ struct vhost_dev {
        int weight;
        int byte_weight;
        u64 kcov_handle;
+       bool use_worker;
        int (*msg_handler)(struct vhost_dev *dev,
                           struct vhost_iotlb_msg *msg);
 };
@@ -161,6 +162,7 @@ struct vhost_dev {
 bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
 void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs,
                    int nvqs, int iov_limit, int weight, int byte_weight,
+                   bool use_worker,
                    int (*msg_handler)(struct vhost_dev *dev,
                                       struct vhost_iotlb_msg *msg));
 long vhost_dev_set_owner(struct vhost_dev *dev);
index fb4e944c4d0d77d18c7aa6ebccecd66e33d0e289..a483cec31d5cbd2f9d69f5caa869b28a98d3fd6c 100644 (file)
@@ -632,7 +632,7 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
 
        vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs),
                       UIO_MAXIOV, VHOST_VSOCK_PKT_WEIGHT,
-                      VHOST_VSOCK_WEIGHT, NULL);
+                      VHOST_VSOCK_WEIGHT, true, NULL);
 
        file->private_data = vsock;
        spin_lock_init(&vsock->send_pkt_list_lock);