From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:19:38
The following patches apply over linus's tree and this patchset
https://lore.kernel.org/all/20211007214448.6282-1-michael.christie@oracle.com/
which allows us to check the vhost owner thread's RLIMITs:
It looks like that patchset has been ok'd by all the major parties
and just needs a small cleanup to apply to Jens and Paul trees, so I
wanted to post my threading patches based over it for review.
The following patches allow us to support multiple vhost workers per
device. I ended up just doing Stefan's original idea where userspace has
the kernel create a worker and we pass back the pid. This has the benefit
over the workqueue and userspace thread approach where we only have
one'ish code path in the kernel during setup to detect old tools. The
main IO paths and device/vq setup/teardown paths all use common code.
I've also included a patch for qemu so you can get an idea of how it
works. If we are ok with the kernel code then I'll break that up into
a patchset and send to qemu-devel for review.
Results:
--------
fio jobs 1 2 4 8 12 16
----------------------------------------------------------
1 worker 84k 492k 510k - - -
worker per vq 184k 380k 744k 1422k 2256k 2434k
Notes:
0. This used a simple fio command:
fio --filename=/dev/sdb --direct=1 --rw=randrw --bs=4k \
--ioengine=libaio --iodepth=128 --numjobs=$JOBS_ABOVE
and I used a VM with 16 vCPUs and 16 virtqueues.
1. The patches were tested with emulate_pr=0 and these patches:
https://lore.kernel.org/all/yq1tuhge4bg.fsf@ca-mkp.ca.oracle.com/t/
which are in mkp's scsi branches for the next kernel. They fix the perf
issues where IOPs dropped at 12 vqs/jobs.
2. Because we have a hard limit of 1024 cmds, if the num jobs * iodepth
was greater than 1024, I would decrease iodepth. So 12 jobs used 85 cmds,
and 16 used 64.
3. The perf issue above at 2 jobs is because when we only have 1 worker
we execute more cmds per vhost_work due to all vqs funneling to one worker.
This results in less context switches and better batching without having to
tweak any settings. I'm working on patches to add back batching during lio
completion and do polling on the submission side.
We will still want the threading patches, because if we batch at the fio
level plus use the vhost theading patches, we can see a big boost like
below. So hopefully doing it at the kernel will allow apps to just work
without having to be smart like fio.
fio using io_uring and batching with the iodepth_batch* settings:
fio jobs 1 2 4 8 12 16
-------------------------------------------------------------
1 worker 494k 520k - - - -
worker per vq 496k 878k 1542k 2436k 2304k 2590k
V3:
- fully convert vhost code to use vq based APIs instead of leaving it
half per dev and half per vq.
- rebase against kernel worker API.
- Drop delayed worker creation. We always create the default worker at
VHOST_SET_OWNER time. Userspace can create and bind workers after that.
v2:
- change loop that we take a refcount to the worker in
- replaced pid == -1 with define.
- fixed tabbing/spacing coding style issue
- use hash instead of list to lookup workers.
- I dropped the patch that added an ioctl cmd to get a vq's worker's
pid. I saw we might do a generic netlink interface instead.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:19:34
This patch adds support for the proposed ioctl that allows userspace
to create virtqueue workers. For vhost-scsi you can set virtqueue_workers
to:
0: default behavior where we have 1 worker for all vqs.
-1: create a worker per vq.
0: create N workers and allow the vqs to share them.
TODO:
- Better support for sharing workers where we bind based on ISR to vq
mapping.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
hw/scsi/vhost-scsi.c | 65 ++++++++++++++++++++
hw/virtio/vhost-backend.c | 8 +++
include/hw/virtio/vhost-backend.h | 4 ++
include/hw/virtio/virtio-scsi.h | 1 +
include/standard-headers/linux/vhost_types.h | 12 ++++
linux-headers/linux/vhost.h | 11 ++++
6 files changed, 101 insertions(+)
@@ -163,6 +163,62 @@ static const VMStateDescription vmstate_virtio_vhost_scsi = {.pre_save=vhost_scsi_pre_save,};+staticintvhost_scsi_set_workers(VHostSCSICommon*vsc,intvq_workers)+{+structvhost_dev*dev=&vsc->dev;+intworkers_per_queue=1,io_queues;+structvhost_vring_workerw;+inti,ret,cnt=0;++if(vq_workers<VHOST_VRING_NEW_WORKER)+return-EINVAL;++if(vq_workers==0||+dev->nvqs==VHOST_SCSI_VQ_NUM_FIXED+1)+/* Use the single default worker */+return0;++io_queues=dev->nvqs-VHOST_SCSI_VQ_NUM_FIXED;+if(vq_workers>0&&io_queues>vq_workers)+workers_per_queue=io_queues/vq_workers;++w.pid=VHOST_VRING_NEW_WORKER;+/*+*ctl/evtsharethefirstworkersinceitwillberareforthem+*tosendcmdswhileIOisrunning.Therestofthevqsgettheir+*ownworker.+*/+for(i=VHOST_SCSI_VQ_NUM_FIXED+1;i<dev->nvqs;i++){+w.index=i;++switch(vq_workers){+caseVHOST_VRING_NEW_WORKER:+w.pid=VHOST_VRING_NEW_WORKER;+break;+default:+/*+*TODO:weshouldgettheISRtovqmappingandbindworkers+*sovqssharingaISRshareaworker.+*/+if(cnt==workers_per_queue){+w.pid=VHOST_VRING_NEW_WORKER;+cnt=0;+}else{+cnt++;+}+}++ret=dev->vhost_ops->vhost_set_vring_worker(dev,&w);+if(ret==-ENOTTY){+ret=0;+break;+}elseif(ret)+break;+}++returnret;+}+staticvoidvhost_scsi_realize(DeviceState*dev,Error**errp){VirtIOSCSICommon*vs=VIRTIO_SCSI_COMMON(dev);
@@ -223,6 +279,13 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)gotofree_vqs;}+ret=vhost_scsi_set_workers(vsc,vs->conf.virtqueue_workers);+if(ret<0){+error_setg(errp,"vhost-scsi: vhost worker setup failed: %s",+strerror(-ret));+gotofree_vqs;+}+/* At present, channel and lun both are 0 for bootable vhost-scsi disk */vsc->channel=0;vsc->lun=0;
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andbindavirtqueuetoitorbindavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevirtqueue.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevirtqueue.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevirtqueueisactive.+*/+#define VHOST_SET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x15, struct vhost_vring_worker)/* The following ioctls use eventfd file descriptors to signal and poll*forevents.*/
--
2.25.1
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:19:43
This patch has the core work queueing function take a worker for when we
support multiple workers. It also adds a helper that takes a vq during
queueing so modules can control which vq/worker to queue work on.
This temp leaves vhost_work_queue. It will be removed when the drivers
are converted in the next patches.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 44 +++++++++++++++++++++++++++----------------
drivers/vhost/vhost.h | 1 +
2 files changed, 29 insertions(+), 16 deletions(-)
@@ -230,6 +230,34 @@ void vhost_poll_stop(struct vhost_poll *poll)}EXPORT_SYMBOL_GPL(vhost_poll_stop);+staticvoidvhost_work_queue_on(structvhost_worker*worker,+structvhost_work*work)+{+if(!worker)+return;++if(!test_and_set_bit(VHOST_WORK_QUEUED,&work->flags)){+/* We can only add the work to the list after we're+*sureitwasnotinthelist.+*test_and_set_bit()impliesamemorybarrier.+*/+llist_add(&work->node,&worker->work_list);+wake_up_process(worker->task);+}+}++voidvhost_work_queue(structvhost_dev*dev,structvhost_work*work)+{+vhost_work_queue_on(dev->worker,work);+}+EXPORT_SYMBOL_GPL(vhost_work_queue);++voidvhost_vq_work_queue(structvhost_virtqueue*vq,structvhost_work*work)+{+vhost_work_queue_on(vq->worker,work);+}+EXPORT_SYMBOL_GPL(vhost_vq_work_queue);+voidvhost_work_dev_flush(structvhost_dev*dev){structvhost_flush_structflush;
@@ -252,22 +280,6 @@ void vhost_poll_flush(struct vhost_poll *poll)}EXPORT_SYMBOL_GPL(vhost_poll_flush);-voidvhost_work_queue(structvhost_dev*dev,structvhost_work*work)-{-if(!dev->worker)-return;--if(!test_and_set_bit(VHOST_WORK_QUEUED,&work->flags)){-/* We can only add the work to the list after we're-*sureitwasnotinthelist.-*test_and_set_bit()impliesamemorybarrier.-*/-llist_add(&work->node,&dev->worker->work_list);-wake_up_process(dev->worker->task);-}-}-EXPORT_SYMBOL_GPL(vhost_work_queue);-/* A lockless hint for busy polling code to exit the loop */boolvhost_vq_has_work(structvhost_virtqueue*vq){
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:19:44
This patch has the core work flush function take a worker for when we
support multiple workers. It also adds a helper that takes a vq during
flushing so modules can control which vq/worker to flush.
This temp leaves vhost_work_dev_flush. It will be removed when the drivers
are converted in the next patches.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 30 +++++++++++++++++++++---------
drivers/vhost/vhost.h | 1 +
2 files changed, 22 insertions(+), 9 deletions(-)
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:20:57
This adds a helper to check if a vq has work pending and converts
vhost-net to use it.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/net.c | 2 +-
drivers/vhost/vhost.c | 6 +++---
drivers/vhost/vhost.h | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
@@ -269,11 +269,11 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)EXPORT_SYMBOL_GPL(vhost_work_queue);/* A lockless hint for busy polling code to exit the loop */-boolvhost_has_work(structvhost_dev*dev)+boolvhost_vq_has_work(structvhost_virtqueue*vq){-returndev->worker&&!llist_empty(&dev->worker->work_list);+returnvq->worker&&!llist_empty(&vq->worker->work_list);}-EXPORT_SYMBOL_GPL(vhost_has_work);+EXPORT_SYMBOL_GPL(vhost_vq_has_work);voidvhost_poll_queue(structvhost_poll*poll){
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:20:57
Convert from vhost dev based helpers to vq ones.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vsock.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
@@ -612,7 +612,7 @@ static int vhost_vsock_start(struct vhost_vsock *vsock)/* Some packets may have been queued before the device was started,*let'skickthesendworkertosendthem.*/-vhost_work_queue(&vsock->dev,&vsock->send_pkt_work);+vhost_vq_work_queue(&vsock->vqs[VSOCK_VQ_TX],&vsock->send_pkt_work);mutex_unlock(&vsock->dev.mutex);return0;
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:20:57
This has the drivers pass in their poll to vq mapping and then converts
the core poll code to use the vq based helpers.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/net.c | 6 ++++--
drivers/vhost/vhost.c | 10 ++++++----
drivers/vhost/vhost.h | 4 +++-
3 files changed, 13 insertions(+), 7 deletions(-)
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:00
With one worker we will always send the scsi cmd responses then send the
TMF rsp, because LIO will always complete the scsi cmds first then call
into us to send the TMF response.
With multiple workers, one of the IO vq threads could be run after the
TMF is queued, so this has us flush all the IO vqs before sending the TMF
response.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/scsi.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:02
Convert from vhost dev based helpers to vq ones.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/scsi.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
@@ -1428,11 +1428,10 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)*indicatethestartoftheflushoperationsothatitwillreach0*whenallthereqsarefinished.*/-for(i=0;i<VHOST_SCSI_MAX_VQ;i++)+for(i=0;i<VHOST_SCSI_MAX_VQ;i++){kref_put(&old_inflight[i]->kref,vhost_scsi_done_inflight);--/* Flush both the vhost poll and vhost work */-vhost_work_dev_flush(&vs->dev);+vhost_vq_work_flush(&vs->vqs[i].vq);+}/* Wait for all reqs issued before the flush to be finished */for(i=0;i<VHOST_SCSI_MAX_VQ;i++)
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:03
vhost_work_queue and vhost_work_dev_flush are no longer used, so drop
them.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 12 ------------
drivers/vhost/vhost.h | 2 --
2 files changed, 14 deletions(-)
@@ -268,24 +268,12 @@ void vhost_vq_work_flush(struct vhost_virtqueue *vq)}EXPORT_SYMBOL_GPL(vhost_vq_work_flush);-voidvhost_work_queue(structvhost_dev*dev,structvhost_work*work)-{-vhost_work_queue_on(dev->worker,work);-}-EXPORT_SYMBOL_GPL(vhost_work_queue);-voidvhost_vq_work_queue(structvhost_virtqueue*vq,structvhost_work*work){vhost_work_queue_on(vq->worker,work);}EXPORT_SYMBOL_GPL(vhost_vq_work_queue);-voidvhost_work_dev_flush(structvhost_dev*dev)-{-vhost_work_flush_on(dev->worker);-}-EXPORT_SYMBOL_GPL(vhost_work_dev_flush);-/* Flush any work that has been scheduled. When calling this, don't hold any*locksthatarealsousedbythecallback.*/voidvhost_poll_flush(structvhost_poll*poll)
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:06
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 99 ++++++++++++++++++++++++++++----
drivers/vhost/vhost.h | 2 +-
include/uapi/linux/vhost.h | 11 ++++
include/uapi/linux/vhost_types.h | 12 ++++
4 files changed, 112 insertions(+), 12 deletions(-)
@@ -617,10 +636,58 @@ static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)free_worker:kfree(worker);-dev->worker=NULL;returnNULL;}+staticstructvhost_worker*vhost_worker_find(structvhost_dev*dev,pid_tpid)+{+structvhost_worker*worker=NULL;+inti;++for(i=0;i<dev->nvqs;i++){+if(dev->vqs[i]->worker->task->pid!=pid)+continue;++worker=dev->vqs[i]->worker;+break;+}++returnworker;+}++/* Caller must have device mutex */+staticintvhost_vq_setup_worker(structvhost_virtqueue*vq,+structvhost_vring_worker*info)+{+structvhost_dev*dev=vq->dev;+structvhost_worker*worker;++if(!dev->use_worker)+return-EINVAL;++/* We don't support setting a worker on an active vq */+if(vq->private_data)+return-EBUSY;++if(info->pid==VHOST_VRING_NEW_WORKER){+worker=vhost_worker_create(dev,1);+if(!worker)+return-ENOMEM;++info->pid=worker->task->pid;+}else{+worker=vhost_worker_find(dev,info->pid);+if(!worker)+return-ENODEV;++refcount_inc(&worker->refcount);+}++vhost_vq_clear_worker(vq);+vq->worker=worker;+return0;+}+/* Caller should have device mutex */longvhost_dev_set_owner(structvhost_dev*dev){
@@ -636,7 +703,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)vhost_attach_mm(dev);if(dev->use_worker){-worker=vhost_worker_create(dev);+worker=vhost_worker_create(dev,dev->nvqs);if(!worker)gotoerr_worker;
@@ -650,7 +717,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)return0;err_iovecs:-vhost_worker_free(dev);+vhost_workers_free(dev);err_worker:vhost_detach_mm(dev);err_mm:
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/+#define VHOST_SET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x15, struct vhost_vring_worker)/* The following ioctls use eventfd file descriptors to signal and poll*forevents.*/
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:07
This patchset allows userspace to map vqs to different workers. This
patch adds a worker pointer to the vq so we can store that info.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 24 +++++++++++++-----------
drivers/vhost/vhost.h | 1 +
2 files changed, 14 insertions(+), 11 deletions(-)
@@ -594,25 +594,24 @@ static int vhost_worker_create(struct vhost_dev *dev)*/task=kernel_worker(vhost_worker,worker,NUMA_NO_NODE,CLONE_FS,KERN_WORKER_NO_FILES|KERN_WORKER_SIG_IGN);-if(IS_ERR(task)){-ret=PTR_ERR(task);+if(IS_ERR(task))gotofree_worker;-}worker->task=task;kernel_worker_start(task,"vhost-%d",current->pid);-return0;+returnworker;free_worker:kfree(worker);dev->worker=NULL;-returnret;+returnNULL;}/* Caller should have device mutex */longvhost_dev_set_owner(structvhost_dev*dev){-interr;+structvhost_worker*worker;+interr,i;/* Is there an owner already? */if(vhost_dev_has_owner(dev)){
@@ -623,9 +622,12 @@ long vhost_dev_set_owner(struct vhost_dev *dev)vhost_attach_mm(dev);if(dev->use_worker){-err=vhost_worker_create(dev);-if(err)+worker=vhost_worker_create(dev);+if(!worker)gotoerr_worker;++for(i=0;i<dev->nvqs;i++)+dev->vqs[i]->worker=worker;}err=vhost_dev_alloc_iovecs(dev);
@@ -80,6 +80,7 @@ struct vhost_vring_call {/* The virtqueue structure describes a queue attached to a device. */structvhost_virtqueue{structvhost_dev*dev;+structvhost_worker*worker;/* The actual ring of buffers. */structmutexmutex;
--
2.25.1
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Mike Christie <michael.christie@oracle.com> Date: 2021-10-22 05:21:14
This patch separates the scsi cmd completion code paths so we can complete
cmds based on their vq instead of having all cmds complete on the same
worker/CPU. This will be useful with the next patches that allow us to
create mulitple worker threads and bind them to different vqs, so we can
have completions running on different threads/CPUs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
drivers/vhost/scsi.c | 48 +++++++++++++++++++++++---------------------
1 file changed, 25 insertions(+), 23 deletions(-)
Unfortunately that patchset in turn triggers kbuild warnings.
I was hoping you would address them, I don't think
merging that patchset before kbuild issues are addressed
is possible.
It also doesn't have lots of acks, I'm a bit apprehensive
of merging core changes like this through the vhost tree.
Try to CC more widely/ping people?
It looks like that patchset has been ok'd by all the major parties
and just needs a small cleanup to apply to Jens and Paul trees, so I
wanted to post my threading patches based over it for review.
The following patches allow us to support multiple vhost workers per
device. I ended up just doing Stefan's original idea where userspace has
the kernel create a worker and we pass back the pid. This has the benefit
over the workqueue and userspace thread approach where we only have
one'ish code path in the kernel during setup to detect old tools. The
main IO paths and device/vq setup/teardown paths all use common code.
I've also included a patch for qemu so you can get an idea of how it
works. If we are ok with the kernel code then I'll break that up into
a patchset and send to qemu-devel for review.
Results:
--------
fio jobs 1 2 4 8 12 16
----------------------------------------------------------
1 worker 84k 492k 510k - - -
worker per vq 184k 380k 744k 1422k 2256k 2434k
Notes:
0. This used a simple fio command:
fio --filename=/dev/sdb --direct=1 --rw=randrw --bs=4k \
--ioengine=libaio --iodepth=128 --numjobs=$JOBS_ABOVE
and I used a VM with 16 vCPUs and 16 virtqueues.
1. The patches were tested with emulate_pr=0 and these patches:
https://lore.kernel.org/all/yq1tuhge4bg.fsf@ca-mkp.ca.oracle.com/t/
which are in mkp's scsi branches for the next kernel. They fix the perf
issues where IOPs dropped at 12 vqs/jobs.
2. Because we have a hard limit of 1024 cmds, if the num jobs * iodepth
was greater than 1024, I would decrease iodepth. So 12 jobs used 85 cmds,
and 16 used 64.
3. The perf issue above at 2 jobs is because when we only have 1 worker
we execute more cmds per vhost_work due to all vqs funneling to one worker.
This results in less context switches and better batching without having to
tweak any settings. I'm working on patches to add back batching during lio
completion and do polling on the submission side.
We will still want the threading patches, because if we batch at the fio
level plus use the vhost theading patches, we can see a big boost like
below. So hopefully doing it at the kernel will allow apps to just work
without having to be smart like fio.
fio using io_uring and batching with the iodepth_batch* settings:
fio jobs 1 2 4 8 12 16
-------------------------------------------------------------
1 worker 494k 520k - - - -
worker per vq 496k 878k 1542k 2436k 2304k 2590k
V3:
- fully convert vhost code to use vq based APIs instead of leaving it
half per dev and half per vq.
- rebase against kernel worker API.
- Drop delayed worker creation. We always create the default worker at
VHOST_SET_OWNER time. Userspace can create and bind workers after that.
v2:
- change loop that we take a refcount to the worker in
- replaced pid == -1 with define.
- fixed tabbing/spacing coding style issue
- use hash instead of list to lookup workers.
- I dropped the patch that added an ioctl cmd to get a vq's worker's
pid. I saw we might do a generic netlink interface instead.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2021-10-22 10:47:20
On Fri, Oct 22, 2021 at 12:19:11AM -0500, Mike Christie wrote:
quoted hunk
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vhost.c | 99 ++++++++++++++++++++++++++++----
drivers/vhost/vhost.h | 2 +-
include/uapi/linux/vhost.h | 11 ++++
include/uapi/linux/vhost_types.h | 12 ++++
4 files changed, 112 insertions(+), 12 deletions(-)
@@ -617,10 +636,58 @@ static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)free_worker:kfree(worker);-dev->worker=NULL;returnNULL;}+staticstructvhost_worker*vhost_worker_find(structvhost_dev*dev,pid_tpid)+{+structvhost_worker*worker=NULL;+inti;++for(i=0;i<dev->nvqs;i++){+if(dev->vqs[i]->worker->task->pid!=pid)+continue;++worker=dev->vqs[i]->worker;+break;+}++returnworker;+}++/* Caller must have device mutex */+staticintvhost_vq_setup_worker(structvhost_virtqueue*vq,+structvhost_vring_worker*info)+{+structvhost_dev*dev=vq->dev;+structvhost_worker*worker;++if(!dev->use_worker)+return-EINVAL;++/* We don't support setting a worker on an active vq */+if(vq->private_data)+return-EBUSY;++if(info->pid==VHOST_VRING_NEW_WORKER){+worker=vhost_worker_create(dev,1);+if(!worker)+return-ENOMEM;++info->pid=worker->task->pid;+}else{+worker=vhost_worker_find(dev,info->pid);+if(!worker)+return-ENODEV;++refcount_inc(&worker->refcount);+}++vhost_vq_clear_worker(vq);+vq->worker=worker;+return0;+}+/* Caller should have device mutex */longvhost_dev_set_owner(structvhost_dev*dev){
@@ -636,7 +703,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)vhost_attach_mm(dev);if(dev->use_worker){-worker=vhost_worker_create(dev);+worker=vhost_worker_create(dev,dev->nvqs);if(!worker)gotoerr_worker;
@@ -650,7 +717,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)return0;err_iovecs:-vhost_worker_free(dev);+vhost_workers_free(dev);err_worker:vhost_detach_mm(dev);err_mm:
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
No need to fix funky things like moving the fd between
pid namespaces while also creating/destroying workers, but let's
document it's not supported.
quoted hunk
+#define VHOST_SET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x15, struct vhost_vring_worker)
/* The following ioctls use eventfd file descriptors to signal and poll
* for events. */
Unfortunately that patchset in turn triggers kbuild warnings.
Yeah, that's the Jens/Paul issue I mentioned. I have to remove the
old create_io_thread code and resolve issues with their trees. Paul's
tree has a conflict with Jens and then my patch has a issue with Paul's
patches.
So Christian and I thought we would re-push the patchset through
Christian after that has settled in 5.16-rc1 and then shoot for 5.17
so it has time to bake in next.
I was hoping you would address them, I don't think
merging that patchset before kbuild issues are addressed
is possible.
It also doesn't have lots of acks, I'm a bit apprehensive
of merging core changes like this through the vhost tree.
Ok. Just to make sure we are on the same page. Christian was going to
push the kernel worker API changes.
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
Ok.
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
This current patchset only allows the vhost_dev owner to
create/bind workers for devices it owns, so namespace don't come
into play. If a thread from another namespace tried to create/bind
a worker we would hit the owner checks in vhost_dev_ioctl which is
done before vhost_vring_ioctl normally (for vdpa we hit the use_worker
check and fail there).
However, with the kernel worker API changes the worker threads will
now be in the vhost dev owner's namespace and not the kthreadd/default
one, so in the future we are covered if we want to do something more
advanced. For example, I've seen people working on an API to export the
worker pids:
https://lore.kernel.org/netdev/20210507154332.hiblsd6ot5wzwkdj@steredhat/T/
and in the future for interfaces that export that info we could restrict
access to root or users from the same namespace or I guess add interfaces
to allow different namespaces to see the workers and share them.
No need to fix funky things like moving the fd between
pid namespaces while also creating/destroying workers, but let's
document it's not supported.
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
Ok.
quoted
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
This current patchset only allows the vhost_dev owner to
create/bind workers for devices it owns, so namespace don't come
I made a mistake here. The patches do restrict VHOST_SET_VRING_WORKER
to the same owner like I wrote. However, it looks like we could have 2
threads with the same mm pointer so vhost_dev_check_owner returns true,
but they could be in different namespaces.
Even though we are not going to pass the pid_t between user/kernel
space, should I add a pid namespace check when I repost the patches?
into play. If a thread from another namespace tried to create/bind
a worker we would hit the owner checks in vhost_dev_ioctl which is
done before vhost_vring_ioctl normally (for vdpa we hit the use_worker
check and fail there).
However, with the kernel worker API changes the worker threads will
now be in the vhost dev owner's namespace and not the kthreadd/default
one, so in the future we are covered if we want to do something more
advanced. For example, I've seen people working on an API to export the
worker pids:
https://lore.kernel.org/netdev/20210507154332.hiblsd6ot5wzwkdj@steredhat/T/
and in the future for interfaces that export that info we could restrict
access to root or users from the same namespace or I guess add interfaces
to allow different namespaces to see the workers and share them.
quoted
No need to fix funky things like moving the fd between
pid namespaces while also creating/destroying workers, but let's
document it's not supported.
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
Ok.
quoted
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
This current patchset only allows the vhost_dev owner to
create/bind workers for devices it owns, so namespace don't come
I made a mistake here. The patches do restrict VHOST_SET_VRING_WORKER
to the same owner like I wrote. However, it looks like we could have 2
threads with the same mm pointer so vhost_dev_check_owner returns true,
but they could be in different namespaces.
Even though we are not going to pass the pid_t between user/kernel
space, should I add a pid namespace check when I repost the patches?
Um it's part of the ioctl. How you are not going to pass it around?
So if we do worry about this, I would just make it a 64 bit integer,
rename it "id" and increment each time a thread is created.
quoted
into play. If a thread from another namespace tried to create/bind
a worker we would hit the owner checks in vhost_dev_ioctl which is
done before vhost_vring_ioctl normally (for vdpa we hit the use_worker
check and fail there).
However, with the kernel worker API changes the worker threads will
now be in the vhost dev owner's namespace and not the kthreadd/default
one, so in the future we are covered if we want to do something more
advanced. For example, I've seen people working on an API to export the
worker pids:
https://lore.kernel.org/netdev/20210507154332.hiblsd6ot5wzwkdj@steredhat/T/
and in the future for interfaces that export that info we could restrict
access to root or users from the same namespace or I guess add interfaces
to allow different namespaces to see the workers and share them.
quoted
No need to fix funky things like moving the fd between
pid namespaces while also creating/destroying workers, but let's
document it's not supported.
Unfortunately that patchset in turn triggers kbuild warnings.
Yeah, that's the Jens/Paul issue I mentioned. I have to remove the
old create_io_thread code and resolve issues with their trees. Paul's
tree has a conflict with Jens and then my patch has a issue with Paul's
patches.
So Christian and I thought we would re-push the patchset through
Christian after that has settled in 5.16-rc1 and then shoot for 5.17
so it has time to bake in next.
Sounds good to me.
quoted
I was hoping you would address them, I don't think
merging that patchset before kbuild issues are addressed
is possible.
It also doesn't have lots of acks, I'm a bit apprehensive
of merging core changes like this through the vhost tree.
Ok. Just to make sure we are on the same page. Christian was going to
push the kernel worker API changes.
On Fri, Oct 22, 2021 at 12:19:06AM -0500, Mike Christie wrote:
quoted hunk
Convert from vhost dev based helpers to vq ones.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vsock.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
I think we should use VSOCK_VQ_RX. I know, the nomenclature is weird,
but it's from the guest's point of view, so the host when sending
packets uses the VSOCK_VQ_RX, see vhost_transport_send_pkt_work().
quoted hunk
rcu_read_unlock();
return len;
@@ -612,7 +612,7 @@ static int vhost_vsock_start(struct vhost_vsock *vsock)
/* Some packets may have been queued before the device was started,
* let's kick the send worker to send them.
*/
- vhost_work_queue(&vsock->dev, &vsock->send_pkt_work);
+ vhost_vq_work_queue(&vsock->vqs[VSOCK_VQ_TX],
&vsock->send_pkt_work);
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
Ok.
quoted
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
This current patchset only allows the vhost_dev owner to
create/bind workers for devices it owns, so namespace don't come
I made a mistake here. The patches do restrict VHOST_SET_VRING_WORKER
to the same owner like I wrote. However, it looks like we could have 2
threads with the same mm pointer so vhost_dev_check_owner returns true,
but they could be in different namespaces.
Even though we are not going to pass the pid_t between user/kernel
space, should I add a pid namespace check when I repost the patches?
Um it's part of the ioctl. How you are not going to pass it around?
The not passing a pid around was referring to your comment about
obfuscating the pid. I might have misunderstood you and thought you
wanted to do something more like you suggested below where to userspace
it's just some int as far as userspace knows.
So if we do worry about this, I would just make it a 64 bit integer,
rename it "id" and increment each time a thread is created.
Yeah, this works for me. I just used a ida to allocate the id. We can
then use it's lookup functions too.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
On Fri, Oct 22, 2021 at 12:19:06AM -0500, Mike Christie wrote:
quoted
Convert from vhost dev based helpers to vq ones.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/vsock.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
I think we should use VSOCK_VQ_RX. I know, the nomenclature is weird, but it's from the guest's point of view, so the host when sending packets uses the VSOCK_VQ_RX, see vhost_transport_send_pkt_work().
quoted
rcu_read_unlock();
return len;
@@ -612,7 +612,7 @@ static int vhost_vsock_start(struct vhost_vsock *vsock)
/* Some packets may have been queued before the device was started,
* let's kick the send worker to send them.
*/
- vhost_work_queue(&vsock->dev, &vsock->send_pkt_work);
+ vhost_vq_work_queue(&vsock->vqs[VSOCK_VQ_TX], &vsock->send_pkt_work);
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/
A couple of things here:
it's probably a good idea not to make it match pid exactly,
if for no other reason than I'm not sure we want to
commit this being a pid. Let's just call it an id?
Ok.
quoted
And maybe byteswap it or xor with some value
just to make sure userspace does not begin abusing it anyway.
Also, interaction with pid namespace is unclear to me.
Can you document what happens here?
This current patchset only allows the vhost_dev owner to
create/bind workers for devices it owns, so namespace don't come
I made a mistake here. The patches do restrict VHOST_SET_VRING_WORKER
to the same owner like I wrote. However, it looks like we could have 2
threads with the same mm pointer so vhost_dev_check_owner returns true,
but they could be in different namespaces.
Even though we are not going to pass the pid_t between user/kernel
space, should I add a pid namespace check when I repost the patches?
Um it's part of the ioctl. How you are not going to pass it around?
The not passing a pid around was referring to your comment about
obfuscating the pid. I might have misunderstood you and thought you
wanted to do something more like you suggested below where to userspace
it's just some int as far as userspace knows.
quoted
So if we do worry about this, I would just make it a 64 bit integer,
rename it "id" and increment each time a thread is created.
Yeah, this works for me. I just used a ida to allocate the id. We can
then use it's lookup functions too.
Probably for the best, linear lookups will make destroying lots of
threads and O(N^2) operation.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Jason Wang <hidden> Date: 2021-10-26 05:37:28
在 2021/10/22 下午1:19, Mike Christie 写道:
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
@@ -617,10 +636,58 @@ static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)free_worker:kfree(worker);-dev->worker=NULL;returnNULL;}+staticstructvhost_worker*vhost_worker_find(structvhost_dev*dev,pid_tpid)+{+structvhost_worker*worker=NULL;+inti;++for(i=0;i<dev->nvqs;i++){+if(dev->vqs[i]->worker->task->pid!=pid)+continue;++worker=dev->vqs[i]->worker;+break;+}++returnworker;+}++/* Caller must have device mutex */+staticintvhost_vq_setup_worker(structvhost_virtqueue*vq,+structvhost_vring_worker*info)+{+structvhost_dev*dev=vq->dev;+structvhost_worker*worker;++if(!dev->use_worker)+return-EINVAL;++/* We don't support setting a worker on an active vq */+if(vq->private_data)+return-EBUSY;
Is it valuable to allow the worker switching on active vq?
@@ -1719,6 +1787,15 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg if (copy_to_user(argp, &s, sizeof(s))) r = -EFAULT; break;+ case VHOST_SET_VRING_WORKER:+ if (copy_from_user(&w, argp, sizeof(w))) {+ r = -EFAULT;+ break;+ }+ r = vhost_vq_setup_worker(vq, &w);+ if (!r && copy_to_user(argp, &w, sizeof(w)))+ r = -EFAULT;+ break; default: r = -ENOIOCTLCMD; }
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/+#define VHOST_SET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x15, struct vhost_vring_worker)/* The following ioctls use eventfd file descriptors to signal and poll*forevents.*/
Do we need VHOST_VRING_FREE_WORKER? And I wonder if using dedicated
ioctls are better:
VHOST_VRING_NEW/FREE_WORKER
VHOST_VRING_ATTACH_WORKER
etc.
Thanks
+
+struct vhost_vring_worker {
+ unsigned int index;
+ /*
+ * The pid of the vhost worker that the vq will be bound to. If
+ * pid is VHOST_VRING_NEW_WORKER a new worker will be created and its
+ * pid will be returned in pid.
+ */
+ __kernel_pid_t pid;
+};
+
/* no alignment requirement */
struct vhost_iotlb_msg {
__u64 iova;
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2021-10-26 13:10:01
On Tue, Oct 26, 2021 at 01:37:14PM +0800, Jason Wang wrote:
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
I think it's a bit much to expect this from management.
@@ -617,10 +636,58 @@ static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)free_worker:kfree(worker);-dev->worker=NULL;returnNULL;}+staticstructvhost_worker*vhost_worker_find(structvhost_dev*dev,pid_tpid)+{+structvhost_worker*worker=NULL;+inti;++for(i=0;i<dev->nvqs;i++){+if(dev->vqs[i]->worker->task->pid!=pid)+continue;++worker=dev->vqs[i]->worker;+break;+}++returnworker;+}++/* Caller must have device mutex */+staticintvhost_vq_setup_worker(structvhost_virtqueue*vq,+structvhost_vring_worker*info)+{+structvhost_dev*dev=vq->dev;+structvhost_worker*worker;++if(!dev->use_worker)+return-EINVAL;++/* We don't support setting a worker on an active vq */+if(vq->private_data)+return-EBUSY;
Is it valuable to allow the worker switching on active vq?
@@ -1719,6 +1787,15 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg if (copy_to_user(argp, &s, sizeof(s))) r = -EFAULT; break;+ case VHOST_SET_VRING_WORKER:+ if (copy_from_user(&w, argp, sizeof(w))) {+ r = -EFAULT;+ break;+ }+ r = vhost_vq_setup_worker(vq, &w);+ if (!r && copy_to_user(argp, &w, sizeof(w)))+ r = -EFAULT;+ break; default: r = -ENOIOCTLCMD; }
@@ -70,6 +70,17 @@#define VHOST_VRING_BIG_ENDIAN 1#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)+/* By default, a device gets one vhost_worker created during VHOST_SET_OWNER+*thatitsvirtqueuesshare.Thisallowsuserspacetocreateavhost_worker+*andmapavirtqueuetoitormapavirtqueuetoanexistingworker.+*+*Ifpid>0anditmatchesanexistingvhost_workerthreaditwillbebound+*tothevq.IfpidisVHOST_VRING_NEW_WORKER,thenanewworkerwillbe+*createdandboundtothevq.+*+*ThismustbecalledafterVHOST_SET_OWNERandbeforethevqisactive.+*/+#define VHOST_SET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x15, struct vhost_vring_worker)/* The following ioctls use eventfd file descriptors to signal and poll*forevents.*/
Do we need VHOST_VRING_FREE_WORKER? And I wonder if using dedicated ioctls
are better:
VHOST_VRING_NEW/FREE_WORKER
VHOST_VRING_ATTACH_WORKER
etc.
Thanks
quoted
+
+struct vhost_vring_worker {
+ unsigned int index;
+ /*
+ * The pid of the vhost worker that the vq will be bound to. If
+ * pid is VHOST_VRING_NEW_WORKER a new worker will be created and its
+ * pid will be returned in pid.
+ */
+ __kernel_pid_t pid;
+};
+
/* no alignment requirement */
struct vhost_iotlb_msg {
__u64 iova;
From: Stefan Hajnoczi <stefanha@redhat.com> Date: 2021-10-26 15:45:06
On Tue, Oct 26, 2021 at 01:37:14PM +0800, Jason Wang wrote:
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
A few options that let the management stack control vhost worker CPU
affinity:
1. The management tool opens the vhost device node, calls
ioctl(VHOST_SET_VRING_WORKER), sets up CPU affinity, and then passes
the fd to the VMM. In this case the VMM is still able to call the
ioctl, which may be undesirable from an attack surface perspective.
2. The VMM calls ioctl(VHOST_SET_VRING_WORKER) itself and the management
tool queries the vq:worker details from the VMM (e.g. a new QEMU QMP
query-vhost-workers command similar to query-iothreads). The
management tool can then control CPU affinity on the vhost worker
threads.
(This is how CPU affinity works in QEMU and libvirt today.)
3. The sysfs approach you suggested. Does sysfs export vq-0/, vq-1/, etc
directories with a "worker" attribute? Do we need to define a point
when the VMM has set up vqs and the management stack is able to query
them? Vhost devices currently pre-allocate the maximum number of vqs
and I'm not sure how to determine the number of vqs that will
actually be used?
One advantage of this is that access to the vq:worker mapping can be
limited to the management stack and the VMM cannot access it. But it
seems a little tricky because the vhost model today doesn't use sysfs
or define a lifecycle where the management stack can configure
devices.
Stefan
From: Stefan Hajnoczi <stefanha@redhat.com> Date: 2021-10-26 16:37:12
On Tue, Oct 26, 2021 at 09:09:52AM -0400, Michael S. Tsirkin wrote:
On Tue, Oct 26, 2021 at 01:37:14PM +0800, Jason Wang wrote:
quoted
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
I think it's a bit much to expect this from management.
The management stack controls the number of vqs used as well as the vCPU
and IOThread CPU affinity. It seems natural for it to also control the
vhost worker CPU affinity. Where else should that be controlled?
Stefan
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM (Qemu etc) or the management stack? If the latter, it looks to me it's better to expose this via sysfs?
I thought it would be where you have management app settings, then the
management app talks to the qemu control interface like it does when it
adds new devices on the fly.
A problem with the management app doing it is to handle the RLIMIT_NPROC
review comment, this patchset:
https://lore.kernel.org/all/20211007214448.6282-1-michael.christie@oracle.com/
basically has the kernel do a clone() from the caller's context. So adding
a worker is like doing the VHOST_SET_OWNER ioctl where it still has to be done
from a process you can inherit values like the mm, cgroups, and now RLIMITs.
Do we need VHOST_VRING_FREE_WORKER? And I wonder if using dedicated ioctls are better:
VHOST_VRING_NEW/FREE_WORKER
VHOST_VRING_ATTACH_WORKER
We didn't need a free worker, because the kernel handles it for userspace. I
tried to make it easy for userspace because in some cases it may not be able
to do syscalls like close on the device. For example if qemu crashes or for
vhost-scsi we don't do an explicit close during VM shutdown.
So we start off with the default worker thread that's used by all vqs like we do
today. Userspace can then override it by creating a new worker. That also unbinds/
detaches the existing worker and does a put on the workers refcount. We also do a
put on the worker when we stop using it during device shutdown/closure/release.
When the worker's refcount goes to zero the kernel deletes it.
I think separating the calls could be helpful though.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Jason Wang <hidden> Date: 2021-10-27 02:55:20
On Tue, Oct 26, 2021 at 11:45 PM Stefan Hajnoczi [off-list ref] wrote:
On Tue, Oct 26, 2021 at 01:37:14PM +0800, Jason Wang wrote:
quoted
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
A few options that let the management stack control vhost worker CPU
affinity:
1. The management tool opens the vhost device node, calls
ioctl(VHOST_SET_VRING_WORKER), sets up CPU affinity, and then passes
the fd to the VMM. In this case the VMM is still able to call the
ioctl, which may be undesirable from an attack surface perspective.
Yes, and we can't do post or dynamic configuration afterwards after
the VM is launched?
2. The VMM calls ioctl(VHOST_SET_VRING_WORKER) itself and the management
tool queries the vq:worker details from the VMM (e.g. a new QEMU QMP
query-vhost-workers command similar to query-iothreads). The
management tool can then control CPU affinity on the vhost worker
threads.
(This is how CPU affinity works in QEMU and libvirt today.)
Then we also need a "bind-vhost-workers" command.
3. The sysfs approach you suggested. Does sysfs export vq-0/, vq-1/, etc
directories with a "worker" attribute?
Something like this.
Do we need to define a point
when the VMM has set up vqs and the management stack is able to query
them?
It could be the point that the vhost fd is opened.
Vhost devices currently pre-allocate the maximum number of vqs
and I'm not sure how to determine the number of vqs that will
actually be used?
It requires more information to be exposed. But before this, we should
allow the dynamic binding of between vq and worker.
One advantage of this is that access to the vq:worker mapping can be
limited to the management stack and the VMM cannot access it. But it
seems a little tricky because the vhost model today doesn't use sysfs
or define a lifecycle where the management stack can configure
devices.
From: Jason Wang <hidden> Date: 2021-10-27 06:03:13
On Wed, Oct 27, 2021 at 12:49 AM [off-list ref] wrote:
On 10/26/21 12:37 AM, Jason Wang wrote:
quoted
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM (Qemu etc) or the management stack? If the latter, it looks to me it's better to expose this via sysfs?
I thought it would be where you have management app settings, then the
management app talks to the qemu control interface like it does when it
adds new devices on the fly.
A problem with the management app doing it is to handle the RLIMIT_NPROC
review comment, this patchset:
https://lore.kernel.org/all/20211007214448.6282-1-michael.christie@oracle.com/
basically has the kernel do a clone() from the caller's context. So adding
a worker is like doing the VHOST_SET_OWNER ioctl where it still has to be done
from a process you can inherit values like the mm, cgroups, and now RLIMITs.
Right, so as Stefan suggested, we probably need new QMP commands then
management can help there. Then it can satisfy the model you described
above.
Do we need VHOST_VRING_FREE_WORKER? And I wonder if using dedicated ioctls are better:
VHOST_VRING_NEW/FREE_WORKER
VHOST_VRING_ATTACH_WORKER
We didn't need a free worker, because the kernel handles it for userspace. I
tried to make it easy for userspace because in some cases it may not be able
to do syscalls like close on the device. For example if qemu crashes or for
vhost-scsi we don't do an explicit close during VM shutdown.
Ok, the motivation is that if in some cases (e.g the active number of
queues are changed), qemu can choose to free some resources.
So we start off with the default worker thread that's used by all vqs like we do
today. Userspace can then override it by creating a new worker. That also unbinds/
detaches the existing worker and does a put on the workers refcount. We also do a
put on the worker when we stop using it during device shutdown/closure/release.
When the worker's refcount goes to zero the kernel deletes it.
I think separating the calls could be helpful though.
From: Stefan Hajnoczi <stefanha@redhat.com> Date: 2021-10-27 09:01:56
On Wed, Oct 27, 2021 at 10:55:04AM +0800, Jason Wang wrote:
On Tue, Oct 26, 2021 at 11:45 PM Stefan Hajnoczi [off-list ref] wrote:
quoted
On Tue, Oct 26, 2021 at 01:37:14PM +0800, Jason Wang wrote:
quoted
在 2021/10/22 下午1:19, Mike Christie 写道:
quoted
This patch allows userspace to create workers and bind them to vqs. You
can have N workers per dev and also share N workers with M vqs.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
A question, who is the best one to determine the binding? Is it the VMM
(Qemu etc) or the management stack? If the latter, it looks to me it's
better to expose this via sysfs?
A few options that let the management stack control vhost worker CPU
affinity:
1. The management tool opens the vhost device node, calls
ioctl(VHOST_SET_VRING_WORKER), sets up CPU affinity, and then passes
the fd to the VMM. In this case the VMM is still able to call the
ioctl, which may be undesirable from an attack surface perspective.
Yes, and we can't do post or dynamic configuration afterwards after
the VM is launched?
Yes, at least it's a little risky for the management stack to keep the
vhost fd open and make ioctl calls while the VMM is using it.
quoted
2. The VMM calls ioctl(VHOST_SET_VRING_WORKER) itself and the management
tool queries the vq:worker details from the VMM (e.g. a new QEMU QMP
query-vhost-workers command similar to query-iothreads). The
management tool can then control CPU affinity on the vhost worker
threads.
(This is how CPU affinity works in QEMU and libvirt today.)
Then we also need a "bind-vhost-workers" command.
The VMM doesn't but the management tool does.
Stefan
From: Stefan Hajnoczi <stefanha@redhat.com> Date: 2021-10-27 09:03:53
On Tue, Oct 26, 2021 at 11:49:37AM -0500, michael.christie@oracle.com wrote:
On 10/26/21 12:37 AM, Jason Wang wrote:
quoted
Do we need VHOST_VRING_FREE_WORKER? And I wonder if using dedicated ioctls are better:
VHOST_VRING_NEW/FREE_WORKER
VHOST_VRING_ATTACH_WORKER
We didn't need a free worker, because the kernel handles it for userspace. I
tried to make it easy for userspace because in some cases it may not be able
to do syscalls like close on the device. For example if qemu crashes or for
vhost-scsi we don't do an explicit close during VM shutdown.
So we start off with the default worker thread that's used by all vqs like we do
today. Userspace can then override it by creating a new worker. That also unbinds/
detaches the existing worker and does a put on the workers refcount. We also do a
put on the worker when we stop using it during device shutdown/closure/release.
When the worker's refcount goes to zero the kernel deletes it.
Please document the worker (p)id lifetime for the ioctl. Otherwise
userspace doesn't know whether a previously created worker is still
alive.
SSTefan