From: Stefan Hajnoczi <stefanha@redhat.com>
To: Connor Kite <connorkite@gmail.com>
Cc: qemu-devel@nongnu.org, "Michael S. Tsirkin" <mst@redhat.com>,
"Stefano Garzarella" <sgarzare@redhat.com>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Gerd Hoffmann" <kraxel@redhat.com>,
"Mathieu Poirier" <mathieu.poirier@linaro.org>,
"Manos Pitsidianakis" <manos.pitsidianakis@linaro.org>,
"Haixu Cui" <quic_haixcui@quicinc.com>,
"Raphael Norwitz" <rnorwitz@nvidia.com>,
"Kevin Wolf" <kwolf@redhat.com>,
"Hanna Reitz" <hreitz@redhat.com>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Fam Zheng" <fam@euphon.net>,
"Milan Zamazal" <mzamazal@redhat.com>,
"Akihiko Odaki" <odaki@rsg.ci.i.u-tokyo.ac.jp>,
"Dmitry Osipenko" <dmitry.osipenko@collabora.com>,
qemu-block@nongnu.org, virtio-fs@lists.linux.dev,
"Gonglei (Arei)" <arei.gonglei@huawei.com>,
"zhenwei pi" <zhenwei.pi@linux.dev>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Eric Blake" <eblake@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Jason Wang" <jasowangio@gmail.com>,
"Peter Xu" <peterx@redhat.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Alyssa Ross" <hi@alyssa.is>,
"Demi Marie Obenour" <demiobenour@gmail.com>
Subject: Re: [PATCH RFC 14/15] hw/virtio/vhost-user: handle data movement with shadow vqs
Date: Tue, 28 Jul 2026 16:57:28 -0400 [thread overview]
Message-ID: <20260728205728.GL371693@fedora> (raw)
In-Reply-To: <20260723-vhost-user-isolated-memory-v1-14-6b97c439eb28@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 9513 bytes --]
On Thu, Jul 23, 2026 at 03:30:13PM -0700, Connor Kite wrote:
> - Add start logic for shadow virtqueues, which sets vring addresses.
> - Update logic for sending vring addresses to backend to point
> to the shadow vrings when isolation mode is active.
> - Implement handlers for intercepted avail and used descriptors. These
> handlers copy buffer contents between bounce buffers in the isolation
> region and the buffers made available by the guest
> - Implement logic to stop svqs
>
> Signed-off-by: Connor Kite <connorkite@gmail.com>
> ---
> hw/virtio/vhost-user.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 166 insertions(+), 1 deletion(-)
>
> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> index 75858289a2..e65f877f9a 100644
> --- a/hw/virtio/vhost-user.c
> +++ b/hw/virtio/vhost-user.c
> @@ -1299,6 +1299,97 @@ static int init_isolation_regions(struct vhost_dev *dev,
> return 0;
> }
>
> +static int vhost_user_memory_lookup(struct vhost_dev *dev, hwaddr gpa,
> + hwaddr *hva)
> +{
> + int i;
> + hwaddr offset;
> +
> + for (i = 0; i < dev->mem->nregions; i++) {
> + struct vhost_memory_region *reg = dev->mem->regions + i;
> +
> + if (gpa >= reg->guest_phys_addr &&
> + reg->guest_phys_addr + reg->memory_size > gpa) {
> + offset = gpa - reg->guest_phys_addr;
> + *hva = reg->userspace_addr + offset;
> + return 0;
> + }
> + }
> +
> + return -EFAULT;
> +}
> +
> +static int vhost_user_svq_handle_used(VhostShadowVirtqueue *svq,
> + VirtQueueElement *elem,
> + void *opaque)
> +{
> + hwaddr hva;
> + int r;
> + struct vhost_dev *dev = opaque;
> +
> + for (int i = 0; i < elem->in_num; i++) {
> + r = vhost_user_memory_lookup(dev, elem->in_addr[i], &hva);
> + if (r < 0) {
> + return r;
> + }
> +
> + memcpy((void *) hva, elem->in_sg[i].iov_base, elem->in_sg[i].iov_len);
> + elem->in_sg[i].iov_base = (void *) hva;
> + }
> +
> + for (int i = 0; i < elem->out_num; i++) {
> + r = vhost_user_memory_lookup(dev, elem->out_addr[i], &hva);
> + if (r < 0) {
> + return r;
> + }
> +
> + memcpy((void *) hva, elem->out_sg[i].iov_base, elem->out_sg[i].iov_len);
> + elem->out_sg[i].iov_base = (void *) hva;
> + }
> +
> + return 0;
> +}
> +
> +static int vhost_user_svq_handle_avail(VhostShadowVirtqueue *svq,
> + VirtQueueElement *elem,
> + void *opaque)
> +{
> + hwaddr offset;
> + const DMAMap *map;
> + DMAMap needle;
> + hwaddr *iova_base;
> +
> + for (int i = 0; i < elem->out_num; i++) {
> + needle.translated_addr = elem->out_addr[i];
> + needle.size = elem->out_sg[i].iov_len - 1;
> + map = vhost_iova_tree_find_gpa(svq->iova_tree, &needle);
Mapping failure must be handled.
> + offset = needle.translated_addr - map->translated_addr;
> + iova_base = (void *)(map->iova + offset);
> +
> + elem->out_sg[i].iov_base = iova_base;
> + memcpy(iova_base, elem->out_sg[i].iov_base, needle.size + 1);
iova_base is an iova, not QEMU memory (HVA). Memcpy cannot be used with
IOVAs. The address of the mapped shared memory is needed as the
destination instead.
> + }
> +
> + for (int i = 0; i < elem->in_num; i++) {
> + needle.translated_addr = elem->in_addr[i];
> + needle.size = elem->in_sg[i].iov_len - 1;
> + map = vhost_iova_tree_find_gpa(svq->iova_tree, &needle);
Mapping failure must be handled.
> + offset = needle.translated_addr - map->translated_addr;
> + iova_base = (void *)(map->iova + offset);
> +
> + elem->in_sg[i].iov_base = iova_base;
> + memcpy(iova_base, elem->in_sg[i].iov_base, needle.size + 1);
No memcpy is necessary before vhost_svq_add() since this is data that
will be read from the device upon I/O completion.
> + }
elem->out_sg[] and elem->in_sg[] are modified in this function. Have we
lost the original I/O buffer memory address from the guest virtqueue?
This is a problem because they will be needed when completing the
request.
> +
> + vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->out_addr,
> + elem->in_sg, elem->in_num, elem->in_addr, elem);
> +
> + return 0;
> +}
> +
> +
> +
> +
> static int vhost_user_set_mem_table(struct vhost_dev *dev,
> struct vhost_memory *mem)
> {
> @@ -1772,6 +1863,8 @@ static int vhost_user_set_vring_err(struct vhost_dev *dev,
> static int vhost_user_set_vring_addr(struct vhost_dev *dev,
> struct vhost_vring_addr *addr)
> {
> + struct vhost_user *u = dev->opaque;
> +
> VhostUserMsg msg = {
> .hdr.request = VHOST_USER_SET_VRING_ADDR,
> .hdr.flags = VHOST_USER_VERSION,
> @@ -1779,6 +1872,25 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev,
> .hdr.size = sizeof(msg.payload.addr),
> };
>
> + if (u->user->memory_isolation) {
> + if (!u->svqs_allocated) {
> + return 0;
> + }
Is the idea that this returns silently when called before
vhost_user_dev_start()? State make code harder to understand. It would
be cleaner to set up the vring addresses without relying on
svqs_allocated. What is the reason for deferring the vring address
setup to vhost_user_dev_start()?
> +
> + int svq_idx = addr->index - dev->vq_index;
> + VhostShadowVirtqueue *svq = g_ptr_array_index(u->shadow_vqs,
> + svq_idx);
> +
> + struct vhost_vring_addr svq_addr = {
> + .avail_user_addr = (uint64_t)(uintptr_t)svq->vring.avail,
> + .desc_user_addr = (uint64_t)(uintptr_t)svq->vring.desc,
> + .used_user_addr = (uint64_t)(uintptr_t)svq->vring.used,
> + .index = addr->index,
> + };
> +
> + msg.payload.addr = svq_addr;
> + }
> +
> /*
> * wait for a reply if logging is enabled to make sure
> * backend is actually logging changes
> @@ -2754,13 +2866,18 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,
> return 0;
> }
>
> +static const VhostShadowVirtqueueOps vhost_user_svq_ops = {
> + .avail_handler = vhost_user_svq_handle_avail,
> + .used_handler = vhost_user_svq_handle_used
> +};
> +
> static void vhost_user_init_svq(struct vhost_dev *dev, struct vhost_user *u)
> {
> /*Modified from vhost-vdpa*/
> u->shadow_vqs = g_ptr_array_new_full(dev->nvqs, vhost_svq_free);
> for (int i = 0; i < dev->nvqs; i++) {
> VhostShadowVirtqueue *svq;
> - svq = vhost_svq_new(NULL, NULL);
> + svq = vhost_svq_new(&vhost_user_svq_ops, dev);
> g_ptr_array_add(u->shadow_vqs, svq);
> }
> }
> @@ -3466,8 +3583,56 @@ void vhost_user_async_close(DeviceState *d,
> }
> }
>
> +static bool vhost_user_svqs_start(struct vhost_dev *dev)
> +{
> + struct vhost_user *u = dev->opaque;
> + uint64_t vring_base = u->iso_memory.vring_base_addr;
> + u->svqs_allocated = true;
Where is this field cleared to false on reset?
> +
> + for (int i = 0; i < u->shadow_vqs->len; i++) {
> + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i);
> + VhostShadowVirtqueue *svq = g_ptr_array_index(u->shadow_vqs, i);
> + svq->base_addr = (hwaddr *) vring_base;
Does this support multiple virtqueues, it looks like they will all use
the same base_addr?
> + vhost_svq_start(svq, dev->vdev, vq, u->iso_iova_tree);
> +
> + struct vhost_vring_addr addr = {
> + .index = dev->vq_index + i,
> + .desc_user_addr = vring_base,
> + .avail_user_addr = vring_base + sizeof(vring_desc_t) *
> + svq->vring.num,
> + .used_user_addr = vring_base + vhost_svq_driver_area_size(svq)
> + };
> +
> + vhost_user_set_vring_addr(dev, &addr);
Also mentioned above in vhost_user_set_vring_addr():
Sending a vhost-user message here is strange since that should already
be done by vhost.c:vhost_virtqueue_start() ->
vhost_user_set_vring_addr().
> +
> + vring_base += vhost_svq_device_area_size(svq) +
> + vhost_svq_driver_area_size(svq);
> + }
> +
> + return false;
> +}
> +
> +static void vhost_user_svqs_stop(struct vhost_dev *dev)
> +{
> + struct vhost_user *u = dev->opaque;
> +
> + for (int i = 0; i < u->shadow_vqs->len; i++) {
> + vhost_svq_stop(g_ptr_array_index(u->shadow_vqs, i));
> + }
> +}
> +
> +
> static int vhost_user_dev_start(struct vhost_dev *dev, bool started)
> {
> + struct vhost_user *u = dev->opaque;
> + if (u->user->memory_isolation) {
> + if (started) {
> + vhost_user_svqs_start(dev);
> + } else {
> + vhost_user_svqs_stop(dev);
> + }
> + }
> +
> if (!vhost_user_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_STATUS)) {
> return 0;
> }
>
> --
> 2.43.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
next prev parent reply other threads:[~2026-07-28 20:57 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 22:29 [PATCH RFC 00/15] vhost-user: isolated memory ConKite
2026-07-23 22:30 ` [PATCH RFC 01/15] vhost-user: Consolidate chardev property definitions ConKite
2026-07-24 6:09 ` Markus Armbruster
2026-07-23 22:30 ` [PATCH RFC 02/15] vhost-user: Add memory-isolation qdev property to vhost-user devices ConKite
2026-07-24 10:56 ` Akihiko Odaki
2026-07-28 18:30 ` Connor Kite
2026-07-23 22:30 ` [PATCH RFC 03/15] backends/cryptodev-vhost-user: add memory isolation bool Connor Kite
2026-07-24 6:06 ` Markus Armbruster
2026-07-27 18:43 ` Stefan Hajnoczi
2026-07-24 11:03 ` Akihiko Odaki
2026-07-23 22:30 ` [PATCH RFC 04/15] net/vhost-user: add memory isolation Connor Kite
2026-07-27 18:48 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 05/15] vhost-user: add memory_isolation to VhostUserState Connor Kite
2026-07-24 11:09 ` Akihiko Odaki
2026-07-27 19:06 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 06/15] util/iova-tree: g_tree_foreach wrapper Connor Kite
2026-07-27 19:07 ` Stefan Hajnoczi
2026-07-28 18:24 ` Connor Kite
2026-07-23 22:30 ` [PATCH RFC 07/15] hw/virtio: iova_tree_foreach wrapper Connor Kite
2026-07-24 11:14 ` Akihiko Odaki
2026-07-23 22:30 ` [PATCH RFC 08/15] hw/virtio/vhost-shadow-virtqueue: used handler Connor Kite
2026-07-24 11:29 ` Akihiko Odaki
2026-07-28 15:06 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 09/15] hw/virtio/vhost-shadow-virtqueue: specified vring placement Connor Kite
2026-07-24 12:19 ` Akihiko Odaki
2026-07-28 15:23 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 10/15] hw/virtio/vhost-shadow-virtqueue: range boundary in translation Connor Kite
2026-07-24 12:31 ` Akihiko Odaki
2026-07-28 15:34 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 11/15] hw/virtio/vhost-user: create isolation region Connor Kite
2026-07-24 12:53 ` Akihiko Odaki
2026-07-28 17:59 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 12/15] hw/virtio/vhost-user: send isolation regions to device Connor Kite
2026-07-24 13:33 ` Akihiko Odaki
2026-07-28 19:16 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 13/15] hw/virtio/vhost-user: add shadow virtqueues and eventfd intercepts Connor Kite
2026-07-24 13:45 ` Akihiko Odaki
2026-07-28 19:41 ` Stefan Hajnoczi
2026-07-23 22:30 ` [PATCH RFC 14/15] hw/virtio/vhost-user: handle data movement with shadow vqs Connor Kite
2026-07-24 15:20 ` Akihiko Odaki
2026-07-28 20:57 ` Stefan Hajnoczi [this message]
2026-07-23 22:30 ` [PATCH RFC 15/15] hw/virtio/vhost-user: shadow vq cleanup Connor Kite
2026-07-24 15:22 ` Akihiko Odaki
2026-07-25 0:15 ` [PATCH RFC 00/15] vhost-user: isolated memory Demi Marie Obenour
2026-07-25 3:45 ` Akihiko Odaki
2026-07-27 18:23 ` Stefan Hajnoczi
2026-07-28 7:07 ` Demi Marie Obenour
2026-07-28 14:50 ` Connor Kite
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260728205728.GL371693@fedora \
--to=stefanha@redhat.com \
--cc=alex.bennee@linaro.org \
--cc=arei.gonglei@huawei.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=connorkite@gmail.com \
--cc=demiobenour@gmail.com \
--cc=dmitry.osipenko@collabora.com \
--cc=eblake@redhat.com \
--cc=eperezma@redhat.com \
--cc=fam@euphon.net \
--cc=hi@alyssa.is \
--cc=hreitz@redhat.com \
--cc=jasowangio@gmail.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=manos.pitsidianakis@linaro.org \
--cc=marcandre.lureau@redhat.com \
--cc=mathieu.poirier@linaro.org \
--cc=mst@redhat.com \
--cc=mzamazal@redhat.com \
--cc=odaki@rsg.ci.i.u-tokyo.ac.jp \
--cc=pbonzini@redhat.com \
--cc=peterx@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=quic_haixcui@quicinc.com \
--cc=rnorwitz@nvidia.com \
--cc=sgarzare@redhat.com \
--cc=viresh.kumar@linaro.org \
--cc=virtio-fs@lists.linux.dev \
--cc=zhenwei.pi@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox