Thread (55 messages) flat view 55 messages, 6 authors, 2021-01-28

Re: Re: [RFC v3 06/11] vhost-vdpa: Add an opaque pointer for vhost IOTLB

From: Yongji Xie <hidden>
Date: 2021-01-27 09:31:04
Also in: kvm, linux-fsdevel

On Wed, Jan 27, 2021 at 11:51 AM Jason Wang [off-list ref] wrote:

On 2021/1/20 下午3:52, Yongji Xie wrote:
quoted
On Wed, Jan 20, 2021 at 2:24 PM Jason Wang [off-list ref] wrote:
quoted
On 2021/1/19 下午12:59, Xie Yongji wrote:
quoted
Add an opaque pointer for vhost IOTLB to store the
corresponding vma->vm_file and offset on the DMA mapping.
Let's split the patch into two.

1) opaque pointer
2) vma stuffs
OK.
quoted
quoted
It will be used in VDUSE case later.

Suggested-by: Jason Wang <redacted>
Signed-off-by: Xie Yongji <redacted>
---
   drivers/vdpa/vdpa_sim/vdpa_sim.c | 11 ++++---
   drivers/vhost/iotlb.c            |  5 ++-
   drivers/vhost/vdpa.c             | 66 +++++++++++++++++++++++++++++++++++-----
   drivers/vhost/vhost.c            |  4 +--
   include/linux/vdpa.h             |  3 +-
   include/linux/vhost_iotlb.h      |  8 ++++-
   6 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index 03c796873a6b..1ffcef67954f 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -279,7 +279,7 @@ static dma_addr_t vdpasim_map_page(struct device *dev, struct page *page,
        */
       spin_lock(&vdpasim->iommu_lock);
       ret = vhost_iotlb_add_range(iommu, pa, pa + size - 1,
-                                 pa, dir_to_perm(dir));
+                                 pa, dir_to_perm(dir), NULL);
Maybe its better to introduce

vhost_iotlb_add_range_ctx() which can accepts the opaque (context). And
let vhost_iotlb_add_range() just call that.
If so, we need export both vhost_iotlb_add_range() and
vhost_iotlb_add_range_ctx() which will be used in VDUSE driver. Is it
a bit redundant?

Probably not, we do something similar in virtio core:

void *virtqueue_get_buf_ctx(struct virtqueue *_vq, unsigned int *len,
                 void **ctx)
{
     struct vring_virtqueue *vq = to_vvq(_vq);

     return vq->packed_ring ? virtqueue_get_buf_ctx_packed(_vq, len, ctx) :
                  virtqueue_get_buf_ctx_split(_vq, len, ctx);
}
EXPORT_SYMBOL_GPL(virtqueue_get_buf_ctx);

void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
{
     return virtqueue_get_buf_ctx(_vq, len, NULL);
}
EXPORT_SYMBOL_GPL(virtqueue_get_buf);
I see. Will do it in the next version.
quoted
quoted
quoted
       spin_unlock(&vdpasim->iommu_lock);
       if (ret)
               return DMA_MAPPING_ERROR;
@@ -317,7 +317,7 @@ static void *vdpasim_alloc_coherent(struct device *dev, size_t size,

               ret = vhost_iotlb_add_range(iommu, (u64)pa,
                                           (u64)pa + size - 1,
-                                         pa, VHOST_MAP_RW);
+                                         pa, VHOST_MAP_RW, NULL);
               if (ret) {
                       *dma_addr = DMA_MAPPING_ERROR;
                       kfree(addr);
@@ -625,7 +625,8 @@ static int vdpasim_set_map(struct vdpa_device *vdpa,
       for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
            map = vhost_iotlb_itree_next(map, start, last)) {
               ret = vhost_iotlb_add_range(vdpasim->iommu, map->start,
-                                         map->last, map->addr, map->perm);
+                                         map->last, map->addr,
+                                         map->perm, NULL);
               if (ret)
                       goto err;
       }
@@ -639,14 +640,14 @@ static int vdpasim_set_map(struct vdpa_device *vdpa,
   }

   static int vdpasim_dma_map(struct vdpa_device *vdpa, u64 iova, u64 size,
-                        u64 pa, u32 perm)
+                        u64 pa, u32 perm, void *opaque)
   {
       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
       int ret;

       spin_lock(&vdpasim->iommu_lock);
       ret = vhost_iotlb_add_range(vdpasim->iommu, iova, iova + size - 1, pa,
-                                 perm);
+                                 perm, NULL);
       spin_unlock(&vdpasim->iommu_lock);

       return ret;
diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
index 0fd3f87e913c..3bd5bd06cdbc 100644
--- a/drivers/vhost/iotlb.c
+++ b/drivers/vhost/iotlb.c
@@ -42,13 +42,15 @@ EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
    * @last: last of IOVA range
    * @addr: the address that is mapped to @start
    * @perm: access permission of this range
+ * @opaque: the opaque pointer for the IOTLB mapping
    *
    * Returns an error last is smaller than start or memory allocation
    * fails
    */
   int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
                         u64 start, u64 last,
-                       u64 addr, unsigned int perm)
+                       u64 addr, unsigned int perm,
+                       void *opaque)
   {
       struct vhost_iotlb_map *map;
@@ -71,6 +73,7 @@ int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
       map->last = last;
       map->addr = addr;
       map->perm = perm;
+     map->opaque = opaque;

       iotlb->nmaps++;
       vhost_iotlb_itree_insert(map, &iotlb->root);
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index 36b6950ba37f..e83e5be7cec8 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -488,6 +488,7 @@ static void vhost_vdpa_iotlb_unmap(struct vhost_vdpa *v, u64 start, u64 last)
       struct vhost_dev *dev = &v->vdev;
       struct vdpa_device *vdpa = v->vdpa;
       struct vhost_iotlb *iotlb = dev->iotlb;
+     struct vhost_iotlb_file *iotlb_file;
       struct vhost_iotlb_map *map;
       struct page *page;
       unsigned long pfn, pinned;
@@ -504,6 +505,10 @@ static void vhost_vdpa_iotlb_unmap(struct vhost_vdpa *v, u64 start, u64 last)
                       }
                       atomic64_sub(map->size >> PAGE_SHIFT,
                                       &dev->mm->pinned_vm);
+             } else if (map->opaque) {
+                     iotlb_file = (struct vhost_iotlb_file *)map->opaque;
+                     fput(iotlb_file->file);
+                     kfree(iotlb_file);
               }
               vhost_iotlb_map_free(iotlb, map);
       }
@@ -540,8 +545,8 @@ static int perm_to_iommu_flags(u32 perm)
       return flags | IOMMU_CACHE;
   }

-static int vhost_vdpa_map(struct vhost_vdpa *v,
-                       u64 iova, u64 size, u64 pa, u32 perm)
+static int vhost_vdpa_map(struct vhost_vdpa *v, u64 iova,
+                       u64 size, u64 pa, u32 perm, void *opaque)
   {
       struct vhost_dev *dev = &v->vdev;
       struct vdpa_device *vdpa = v->vdpa;
@@ -549,12 +554,12 @@ static int vhost_vdpa_map(struct vhost_vdpa *v,
       int r = 0;

       r = vhost_iotlb_add_range(dev->iotlb, iova, iova + size - 1,
-                               pa, perm);
+                               pa, perm, opaque);
       if (r)
               return r;

       if (ops->dma_map) {
-             r = ops->dma_map(vdpa, iova, size, pa, perm);
+             r = ops->dma_map(vdpa, iova, size, pa, perm, opaque);
       } else if (ops->set_map) {
               if (!v->in_batch)
                       r = ops->set_map(vdpa, dev->iotlb);
@@ -591,6 +596,51 @@ static void vhost_vdpa_unmap(struct vhost_vdpa *v, u64 iova, u64 size)
       }
   }

+static int vhost_vdpa_sva_map(struct vhost_vdpa *v,
+                           u64 iova, u64 size, u64 uaddr, u32 perm)
+{
+     u64 offset, map_size, map_iova = iova;
+     struct vhost_iotlb_file *iotlb_file;
+     struct vm_area_struct *vma;
+     int ret;
Lacking mmap_read_lock().
Good catch! Will fix it.
quoted
quoted
+
+     while (size) {
+             vma = find_vma(current->mm, uaddr);
+             if (!vma) {
+                     ret = -EINVAL;
+                     goto err;
+             }
+             map_size = min(size, vma->vm_end - uaddr);
+             offset = (vma->vm_pgoff << PAGE_SHIFT) + uaddr - vma->vm_start;
+             iotlb_file = NULL;
+             if (vma->vm_file && (vma->vm_flags & VM_SHARED)) {
I wonder if we need more strict check here. When developing vhost-vdpa,
I try hard to make sure the map can only work for user pages.

So the question is: do we need to exclude MMIO area or only allow shmem
to work here?
Do you mean we need to check VM_MIXEDMAP | VM_PFNMAP here?

I meant do we need to allow VM_IO here? (We don't allow such case in
vhost-vdpa now).
OK, let's exclude the vma with VM_IO | VM_PFNMAP.
quoted
It makes sense to me.
quoted
quoted
+                     iotlb_file = kmalloc(sizeof(*iotlb_file), GFP_KERNEL);
+                     if (!iotlb_file) {
+                             ret = -ENOMEM;
+                             goto err;
+                     }
+                     iotlb_file->file = get_file(vma->vm_file);
+                     iotlb_file->offset = offset;
+             }
I wonder if it's better to allocate iotlb_file and make iotlb_file->file
= NULL && iotlb_file->offset = 0. This can force a consistent code for
the vDPA parents.
Looks fine to me.
quoted
Or we can simply fail the map without a file as backend.
Actually there will be some vma without vm_file during vm booting.

Yes, e.g bios or other rom. Vhost-user has the similar issue and they
filter the out them in qemu.

For vhost-vDPA, consider it can supports various difference backends, we
can't do that.
OK, I will transfer iotlb_file with NULL file and let the backend do
the filtering.

Thanks,
Yongji
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help