All of lore.kernel.org
 help / color / mirror / Atom feed
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 --]

  parent reply	other threads:[~2026-07-28 20:57 UTC|newest]

Thread overview: 49+ 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-28  5:26       ` Connor Kite
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.