qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH 02/18] vdpa: move iova tree to the shared struct


From: Eugenio Perez Martin
Subject: Re: [RFC PATCH 02/18] vdpa: move iova tree to the shared struct
Date: Fri, 24 Nov 2023 18:11:44 +0100

On Thu, Nov 2, 2023 at 10:37 AM Si-Wei Liu <si-wei.liu@oracle.com> wrote:
>
>
>
> On 10/19/2023 7:34 AM, Eugenio Pérez wrote:
> > Next patches will register the vhost_vdpa memory listener while the VM
> > is migrating at the destination, so we can map the memory to the device
> > before stopping the VM at the source.  The main goal is to reduce the
> > downtime.
> >
> > However, the destination QEMU is unaware of which vhost_vdpa device will
> > register its memory_listener.  If the source guest has CVQ enabled, it
> > will be the CVQ device.  Otherwise, it  will be the first one.
> >
> > Move the iova tree to VhostVDPAShared so all vhost_vdpa can use it,
> > rather than always in the first or last vhost_vdpa.
> >
> > Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> > ---
> >   include/hw/virtio/vhost-vdpa.h |  4 +--
> >   hw/virtio/vhost-vdpa.c         | 19 ++++++------
> >   net/vhost-vdpa.c               | 54 +++++++++++++++-------------------
> >   3 files changed, 35 insertions(+), 42 deletions(-)
> >
> > diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
> > index eb1a56d75a..ac036055d3 100644
> > --- a/include/hw/virtio/vhost-vdpa.h
> > +++ b/include/hw/virtio/vhost-vdpa.h
> > @@ -32,6 +32,8 @@ typedef struct VhostVDPAHostNotifier {
> >
> >   /* Info shared by all vhost_vdpa device models */
> >   typedef struct vhost_vdpa_shared {
> > +    /* IOVA mapping used by the Shadow Virtqueue */
> > +    VhostIOVATree *iova_tree;
> >   } VhostVDPAShared;
> >
> >   typedef struct vhost_vdpa {
> > @@ -48,8 +50,6 @@ typedef struct vhost_vdpa {
> >       bool shadow_data;
> >       /* Device suspended successfully */
> >       bool suspended;
> > -    /* IOVA mapping used by the Shadow Virtqueue */
> > -    VhostIOVATree *iova_tree;
> >       VhostVDPAShared *shared;
> >       GPtrArray *shadow_vqs;
> >       const VhostShadowVirtqueueOps *shadow_vq_ops;
> > diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
> > index 819b2d811a..9cee38cb6d 100644
> > --- a/hw/virtio/vhost-vdpa.c
> > +++ b/hw/virtio/vhost-vdpa.c
> > @@ -358,7 +358,7 @@ static void 
> > vhost_vdpa_listener_region_add(MemoryListener *listener,
> >           mem_region.size = int128_get64(llsize) - 1,
> >           mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly),
> >
> > -        r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region);
> > +        r = vhost_iova_tree_map_alloc(v->shared->iova_tree, &mem_region);
> >           if (unlikely(r != IOVA_OK)) {
> >               error_report("Can't allocate a mapping (%d)", r);
> >               goto fail;
> > @@ -379,7 +379,7 @@ static void 
> > vhost_vdpa_listener_region_add(MemoryListener *listener,
> >
> >   fail_map:
> >       if (v->shadow_data) {
> > -        vhost_iova_tree_remove(v->iova_tree, mem_region);
> > +        vhost_iova_tree_remove(v->shared->iova_tree, mem_region);
> >       }
> >
> >   fail:
> > @@ -441,13 +441,13 @@ static void 
> > vhost_vdpa_listener_region_del(MemoryListener *listener,
> >               .size = int128_get64(llsize) - 1,
> >           };
> >
> > -        result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region);
> > +        result = vhost_iova_tree_find_iova(v->shared->iova_tree, 
> > &mem_region);
> >           if (!result) {
> >               /* The memory listener map wasn't mapped */
> >               return;
> >           }
> >           iova = result->iova;
> > -        vhost_iova_tree_remove(v->iova_tree, *result);
> > +        vhost_iova_tree_remove(v->shared->iova_tree, *result);
> >       }
> >       vhost_vdpa_iotlb_batch_begin_once(v);
> >       /*
> > @@ -1059,7 +1059,8 @@ static void vhost_vdpa_svq_unmap_ring(struct 
> > vhost_vdpa *v, hwaddr addr)
> >       const DMAMap needle = {
> >           .translated_addr = addr,
> >       };
> > -    const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, 
> > &needle);
> > +    const DMAMap *result = vhost_iova_tree_find_iova(v->shared->iova_tree,
> > +                                                     &needle);
> >       hwaddr size;
> >       int r;
> >
> > @@ -1075,7 +1076,7 @@ static void vhost_vdpa_svq_unmap_ring(struct 
> > vhost_vdpa *v, hwaddr addr)
> >           return;
> >       }
> >
> > -    vhost_iova_tree_remove(v->iova_tree, *result);
> > +    vhost_iova_tree_remove(v->shared->iova_tree, *result);
> >   }
> >
> >   static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
> > @@ -1103,7 +1104,7 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa 
> > *v, DMAMap *needle,
> >   {
> >       int r;
> >
> > -    r = vhost_iova_tree_map_alloc(v->iova_tree, needle);
> > +    r = vhost_iova_tree_map_alloc(v->shared->iova_tree, needle);
> >       if (unlikely(r != IOVA_OK)) {
> >           error_setg(errp, "Cannot allocate iova (%d)", r);
> >           return false;
> > @@ -1115,7 +1116,7 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa 
> > *v, DMAMap *needle,
> >                              needle->perm == IOMMU_RO);
> >       if (unlikely(r != 0)) {
> >           error_setg_errno(errp, -r, "Cannot map region to device");
> > -        vhost_iova_tree_remove(v->iova_tree, *needle);
> > +        vhost_iova_tree_remove(v->shared->iova_tree, *needle);
> >       }
> >
> >       return r == 0;
> > @@ -1216,7 +1217,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev 
> > *dev)
> >               goto err;
> >           }
> >
> > -        vhost_svq_start(svq, dev->vdev, vq, v->iova_tree);
> > +        vhost_svq_start(svq, dev->vdev, vq, v->shared->iova_tree);
> >           ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err);
> >           if (unlikely(!ok)) {
> >               goto err_map;
> > diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> > index a2f9855288..15e7579b13 100644
> > --- a/net/vhost-vdpa.c
> > +++ b/net/vhost-vdpa.c
> > @@ -345,8 +345,8 @@ static void 
> > vhost_vdpa_net_data_start_first(VhostVDPAState *s)
> >
> >       add_migration_state_change_notifier(&s->migration_state);
> >       if (v->shadow_vqs_enabled) {
> > -        v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
> > -                                           v->iova_range.last);
> > +        v->shared->iova_tree = vhost_iova_tree_new(v->iova_range.first,
> > +                                                   v->iova_range.last);
> This code change is okay so far without .load_setup involved, but if
> interacting with .load_setup the iova_tree can be NULL when x-svq=on.
> Below is a stacktrace showing the problem.
>

Right, the next version of the series including .load_setup will take
this into account. Thanks!

> #0  0x00005582bf00944c in vhost_iova_tree_map_alloc (tree=0x0,
> map=map@entry=0x7fb16bfffde0) at ../hw/virtio/vhost-iova-tree.c:89
> #1  0x00005582bee8cdb3 in vhost_vdpa_listener_region_add
> (listener=0x5582c138ee58, section=0x7fb16bfffe50)
>      at ../include/qemu/int128.h:33
> #2  0x00005582bf029d4b in memory_listener_register (as=0x5582bfb53d20
> <address_space_memory>, listener=0x5582c138ee58)
>      at ../system/memory.c:3026
> #3  0x00005582bf029d4b in memory_listener_register
> (listener=0x5582c138ee58, as=0x5582bfb53d20 <address_space_memory>)
>      at ../system/memory.c:3096
> #4  0x00005582bee8e712 in vhost_vdpa_load_setup (shared=0x5582c138ee50,
> dma_as=0x5582bfb53d20 <address_space_memory>)
>      at ../hw/virtio/vhost-vdpa.c:1550
> #5  0x00005582bef0b7df in vhost_vdpa_net_load_setup (nc=0x7fb172a27010,
> nic=<optimized out>) at ../net/vhost-vdpa.c:415
> #6  0x00005582beeeb4f5 in qemu_loadvm_state (f=0x5582c1c1a800) at
> ../migration/savevm.c:2682
> #7  0x00005582beeeb4f5 in qemu_loadvm_state (f=0x5582c1c1a800) at
> ../migration/savevm.c:2866
> #8  0x00005582beed5e17 in process_incoming_migration_co
> (opaque=<optimized out>) at ../migration/migration.c:548
> #9  0x00005582bf21b29b in coroutine_trampoline (i0=<optimized out>,
> i1=<optimized out>) at ../util/coroutine-ucontext.c:177
> #10 0x00007fb16e448190 in __start_context () at /lib64/libc.so.6
>
> -Siwei
> >       }
> >   }
> >
> > @@ -371,11 +371,6 @@ static int vhost_vdpa_net_data_start(NetClientState 
> > *nc)
> >           return 0;
> >       }
> >
> > -    if (v->shadow_vqs_enabled) {
> > -        VhostVDPAState *s0 = vhost_vdpa_net_first_nc_vdpa(s);
> > -        v->iova_tree = s0->vhost_vdpa.iova_tree;
> > -    }
> > -
> >       return 0;
> >   }
> >
> > @@ -408,9 +403,8 @@ static void vhost_vdpa_net_client_stop(NetClientState 
> > *nc)
> >
> >       dev = s->vhost_vdpa.dev;
> >       if (dev->vq_index + dev->nvqs == dev->vq_index_end) {
> > -        g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete);
> > -    } else {
> > -        s->vhost_vdpa.iova_tree = NULL;
> > +        g_clear_pointer(&s->vhost_vdpa.shared->iova_tree,
> > +                        vhost_iova_tree_delete);
> >       }
> >   }
> >
> > @@ -464,7 +458,7 @@ static int vhost_vdpa_set_address_space_id(struct 
> > vhost_vdpa *v,
> >
> >   static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr)
> >   {
> > -    VhostIOVATree *tree = v->iova_tree;
> > +    VhostIOVATree *tree = v->shared->iova_tree;
> >       DMAMap needle = {
> >           /*
> >            * No need to specify size or to look for more translations since
> > @@ -498,7 +492,7 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, 
> > void *buf, size_t size,
> >       map.translated_addr = (hwaddr)(uintptr_t)buf;
> >       map.size = size - 1;
> >       map.perm = write ? IOMMU_RW : IOMMU_RO,
> > -    r = vhost_iova_tree_map_alloc(v->iova_tree, &map);
> > +    r = vhost_iova_tree_map_alloc(v->shared->iova_tree, &map);
> >       if (unlikely(r != IOVA_OK)) {
> >           error_report("Cannot map injected element");
> >           return r;
> > @@ -513,7 +507,7 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, 
> > void *buf, size_t size,
> >       return 0;
> >
> >   dma_map_err:
> > -    vhost_iova_tree_remove(v->iova_tree, map);
> > +    vhost_iova_tree_remove(v->shared->iova_tree, map);
> >       return r;
> >   }
> >
> > @@ -573,24 +567,22 @@ out:
> >           return 0;
> >       }
> >
> > -    if (s0->vhost_vdpa.iova_tree) {
> > -        /*
> > -         * SVQ is already configured for all virtqueues.  Reuse IOVA tree 
> > for
> > -         * simplicity, whether CVQ shares ASID with guest or not, because:
> > -         * - Memory listener need access to guest's memory addresses 
> > allocated
> > -         *   in the IOVA tree.
> > -         * - There should be plenty of IOVA address space for both ASID 
> > not to
> > -         *   worry about collisions between them.  Guest's translations are
> > -         *   still validated with virtio virtqueue_pop so there is no risk 
> > for
> > -         *   the guest to access memory that it shouldn't.
> > -         *
> > -         * To allocate a iova tree per ASID is doable but it complicates 
> > the
> > -         * code and it is not worth it for the moment.
> > -         */
> > -        v->iova_tree = s0->vhost_vdpa.iova_tree;
> > -    } else {
> > -        v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
> > -                                           v->iova_range.last);
> > +    /*
> > +     * If other vhost_vdpa already have an iova_tree, reuse it for 
> > simplicity,
> > +     * whether CVQ shares ASID with guest or not, because:
> > +     * - Memory listener need access to guest's memory addresses allocated 
> > in
> > +     *   the IOVA tree.
> > +     * - There should be plenty of IOVA address space for both ASID not to
> > +     *   worry about collisions between them.  Guest's translations are 
> > still
> > +     *   validated with virtio virtqueue_pop so there is no risk for the 
> > guest
> > +     *   to access memory that it shouldn't.
> > +     *
> > +     * To allocate a iova tree per ASID is doable but it complicates the 
> > code
> > +     * and it is not worth it for the moment.
> > +     */
> > +    if (!v->shared->iova_tree) {
> > +        v->shared->iova_tree = vhost_iova_tree_new(v->iova_range.first,
> > +                                                   v->iova_range.last);
> >       }
> >
> >       r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer,
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]