On Tue, Jan 21, 2025 at 3:53 PM Jonah Palmer <jonah.pal...@oracle.com> wrote:
>
>
>
> On 1/16/25 11:44 AM, Eugenio Perez Martin wrote:
> > On Fri, Jan 10, 2025 at 6:09 PM Jonah Palmer <jonah.pal...@oracle.com> 
> > wrote:
> >>
> >> Decouples the IOVA allocator from the full IOVA->HVA tree to support a
> >> SVQ IOVA->HVA tree for host-only memory mappings.
> >>
> >> The IOVA allocator still allocates an IOVA range but instead adds this
> >> range to an IOVA-only tree (iova_map) that keeps track of allocated IOVA
> >> ranges for both guest & host-only memory mappings.
> >>
> >> A new API function vhost_iova_tree_insert() is also created for adding
> >> IOVA->HVA mappings into the SVQ IOVA->HVA tree, since the allocator is
> >> no longer doing that.
> >>
> >
> > What is the reason for not adding IOVA -> HVA tree on _alloc
> > automatically? The problematic one is GPA -> HVA, isn't it? Doing this
> > way we force all the allocations to do the two calls (alloc+insert),
> > or the trees will be inconsistent.
> >
>
> Ah, I believe you also made a similar comment in RFC v1, saying it
> wasn't intuitive for the user to follow up with a
> vhost_iova_tree_insert() call afterwards (e.g. in
> vhost_vdpa_svq_map_ring() or vhost_vdpa_cvq_map_buf()).
>
> I believe what I ended up doing in RFC v2 was creating separate alloc
> functions for host-only memory mapping (e.g. vhost_vdpa_svq_map_ring()
> and vhost_vdpa_cvq_map_buf()) and guest-backed memory mapping (e.g.
> vhost_vdpa_listener_region_add()).
>
> This way, for host-only memory, in the alloc function we allocate an
> IOVA range (in the IOVA-only tree) and then also inserts the IOVA->HVA
> mapping into the SVQ IOVA->HVA tree. Similarly, for guest-backed memory,
> we create its own alloc function (e.g. vhost_iova_tree_map_alloc_gpa()),
> allocate the IOVA range (in the IOVA-only tree) and then insert the
> GPA->IOVA mapping into the GPA->IOVA tree.
>
> This was done so that we didn't have to rely on the user to also call
> the insertion function after calling the allocation function.
>
> Is this kinda what you're thinking of here?
>

Right, I think it makes more sense. Do you think differently, maybe I
missed any drawbacks?

> >> Signed-off-by: Jonah Palmer <jonah.pal...@oracle.com>
> >> ---
> >>   hw/virtio/vhost-iova-tree.c | 35 +++++++++++++++++++++++++++++++----
> >>   hw/virtio/vhost-iova-tree.h |  1 +
> >>   hw/virtio/vhost-vdpa.c      | 21 ++++++++++++++++-----
> >>   net/vhost-vdpa.c            | 13 +++++++++++--
> >>   4 files changed, 59 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c
> >> index 3d03395a77..b1cfd17843 100644
> >> --- a/hw/virtio/vhost-iova-tree.c
> >> +++ b/hw/virtio/vhost-iova-tree.c
> >> @@ -28,12 +28,15 @@ struct VhostIOVATree {
> >>
> >>       /* IOVA address to qemu memory maps. */
> >>       IOVATree *iova_taddr_map;
> >> +
> >> +    /* Allocated IOVA addresses */
> >> +    IOVATree *iova_map;
> >>   };
> >>
> >>   /**
> >> - * Create a new IOVA tree
> >> + * Create a new VhostIOVATree
> >>    *
> >> - * Returns the new IOVA tree
> >> + * Returns the new VhostIOVATree
> >>    */
> >>   VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
> >>   {
> >> @@ -44,15 +47,17 @@ VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, 
> >> hwaddr iova_last)
> >>       tree->iova_last = iova_last;
> >>
> >>       tree->iova_taddr_map = iova_tree_new();
> >> +    tree->iova_map = iova_tree_new();
> >>       return tree;
> >>   }
> >>
> >>   /**
> >> - * Delete an iova tree
> >> + * Delete a VhostIOVATree
> >
> > Thanks for fixing the doc of new and delete :) Maybe it is better to
> > put it in an independent patch?
> >
>
> Sure can :)
>
> >>    */
> >>   void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
> >>   {
> >>       iova_tree_destroy(iova_tree->iova_taddr_map);
> >> +    iova_tree_destroy(iova_tree->iova_map);
> >>       g_free(iova_tree);
> >>   }
> >>
> >> @@ -94,7 +99,7 @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, 
> >> DMAMap *map)
> >>       }
> >>
> >>       /* Allocate a node in IOVA address */
> >> -    return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
> >> +    return iova_tree_alloc_map(tree->iova_map, map, iova_first,
> >>                                  tree->iova_last);
> >>   }
> >>
> >> @@ -107,4 +112,26 @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, 
> >> DMAMap *map)
> >>   void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map)
> >>   {
> >>       iova_tree_remove(iova_tree->iova_taddr_map, map);
> >> +    iova_tree_remove(iova_tree->iova_map, map);
> >> +}
> >> +
> >> +/**
> >> + * Insert a new mapping to the IOVA->HVA tree
> >> + *
> >> + * @tree: The VhostIOVATree
> >> + * @map: The IOVA->HVA mapping
> >> + *
> >> + * Returns:
> >> + * - IOVA_OK if the map fits in the container
> >> + * - IOVA_ERR_INVALID if the map does not make sense (e.g. size overflow)
> >> + * - IOVA_ERR_OVERLAP if the IOVA range overlaps with an existing range
> >> + */
> >> +int vhost_iova_tree_insert(VhostIOVATree *iova_tree, DMAMap *map)
> >> +{
> >> +    if (map->translated_addr + map->size < map->translated_addr ||
> >> +        map->perm == IOMMU_NONE) {
> >> +        return IOVA_ERR_INVALID;
> >> +    }
> >> +
> >> +    return iova_tree_insert(iova_tree->iova_taddr_map, map);
> >>   }
> >> diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h
> >> index 4adfd79ff0..8bf7b64786 100644
> >> --- a/hw/virtio/vhost-iova-tree.h
> >> +++ b/hw/virtio/vhost-iova-tree.h
> >> @@ -23,5 +23,6 @@ const DMAMap *vhost_iova_tree_find_iova(const 
> >> VhostIOVATree *iova_tree,
> >>                                           const DMAMap *map);
> >>   int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map);
> >>   void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map);
> >> +int vhost_iova_tree_insert(VhostIOVATree *iova_tree, DMAMap *map);
> >>
> >>   #endif
> >> diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
> >> index 3cdaa12ed5..f5803f35f4 100644
> >> --- a/hw/virtio/vhost-vdpa.c
> >> +++ b/hw/virtio/vhost-vdpa.c
> >> @@ -1142,18 +1142,29 @@ static void vhost_vdpa_svq_unmap_rings(struct 
> >> vhost_dev *dev,
> >>    *
> >>    * @v: Vhost-vdpa device
> >>    * @needle: The area to search iova
> >> + * @taddr: The translated address (SVQ HVA)
> >>    * @errorp: Error pointer
> >>    */
> >>   static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle,
> >> -                                    Error **errp)
> >> +                                    hwaddr taddr, Error **errp)
> >>   {
> >>       int r;
> >>
> >> +    /* Allocate an IOVA range in the IOVA tree */
> >>       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;
> >>       }
> >> +    needle->translated_addr = taddr;
> >> +
> >> +    /* Add IOVA->HVA mapping to the IOVA->HVA tree */
> >> +    r = vhost_iova_tree_insert(v->shared->iova_tree, needle);
> >> +    if (unlikely(r != IOVA_OK)) {
> >> +        error_setg(errp, "Cannot add SVQ vring mapping (%d)", r);
> >> +        vhost_iova_tree_remove(v->shared->iova_tree, *needle);
> >> +        return false;
> >> +    }
> >>
> >>       r = vhost_vdpa_dma_map(v->shared, v->address_space_id, needle->iova,
> >>                              needle->size + 1,
> >> @@ -1192,11 +1203,11 @@ static bool vhost_vdpa_svq_map_rings(struct 
> >> vhost_dev *dev,
> >>       vhost_svq_get_vring_addr(svq, &svq_addr);
> >>
> >>       driver_region = (DMAMap) {
> >> -        .translated_addr = svq_addr.desc_user_addr,
> >>           .size = driver_size - 1,
> >>           .perm = IOMMU_RO,
> >>       };
> >> -    ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp);
> >> +    ok = vhost_vdpa_svq_map_ring(v, &driver_region, 
> >> svq_addr.desc_user_addr,
> >> +                                 errp);
> >>       if (unlikely(!ok)) {
> >>           error_prepend(errp, "Cannot create vq driver region: ");
> >>           return false;
> >> @@ -1206,11 +1217,11 @@ static bool vhost_vdpa_svq_map_rings(struct 
> >> vhost_dev *dev,
> >>       addr->avail_user_addr = driver_region.iova + avail_offset;
> >>
> >>       device_region = (DMAMap) {
> >> -        .translated_addr = svq_addr.used_user_addr,
> >>           .size = device_size - 1,
> >>           .perm = IOMMU_RW,
> >>       };
> >> -    ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
> >> +    ok = vhost_vdpa_svq_map_ring(v, &device_region, 
> >> svq_addr.used_user_addr,
> >> +                                 errp);
> >>       if (unlikely(!ok)) {
> >>           error_prepend(errp, "Cannot create vq device region: ");
> >>           vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr);
> >> diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> >> index 231b45246c..1ef555e04e 100644
> >> --- a/net/vhost-vdpa.c
> >> +++ b/net/vhost-vdpa.c
> >> @@ -512,14 +512,23 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa 
> >> *v, void *buf, size_t size,
> >>       DMAMap map = {};
> >>       int r;
> >>
> >> -    map.translated_addr = (hwaddr)(uintptr_t)buf;
> >>       map.size = size - 1;
> >>       map.perm = write ? IOMMU_RW : IOMMU_RO,
> >> +
> >> +    /* Allocate an IOVA range in the IOVA tree */
> >>       r = vhost_iova_tree_map_alloc(v->shared->iova_tree, &map);
> >>       if (unlikely(r != IOVA_OK)) {
> >> -        error_report("Cannot map injected element");
> >> +        error_report("Cannot allocate IOVA range for injected element");
> >>           return r;
> >>       }
> >> +    map.translated_addr = (hwaddr)(uintptr_t)buf;
> >> +
> >> +    /* Add IOVA->HVA mapping to the IOVA->HVA tree */
> >> +    r = vhost_iova_tree_insert(v->shared->iova_tree, &map);
> >> +    if (unlikely(r != IOVA_OK)) {
> >> +        error_report("Cannot map injected element into IOVA->HVA tree");
> >> +        goto dma_map_err;
> >> +    }
> >>
> >>       r = vhost_vdpa_dma_map(v->shared, v->address_space_id, map.iova,
> >>                              vhost_vdpa_net_cvq_cmd_page_len(), buf, 
> >> !write);
> >> --
> >> 2.43.5
> >>
> >
>


Reply via email to