vhost: invalidate vring in case of matching IOTLB invalidate
authorMaxime Coquelin <maxime.coquelin@redhat.com>
Thu, 5 Oct 2017 08:36:26 +0000 (10:36 +0200)
committerYuanhan Liu <yliu@fridaylinux.org>
Tue, 10 Oct 2017 13:52:27 +0000 (15:52 +0200)
As soon as a page used by a ring is invalidated, the access_ok flag
is cleared, so that processing threads try to map them again.

Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
lib/librte_vhost/vhost.c
lib/librte_vhost/vhost.h
lib/librte_vhost/vhost_user.c

index 65606f6..54a1864 100644 (file)
@@ -173,6 +173,21 @@ out:
        return 0;
 }
 
+void
+vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq)
+{
+       if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
+               vhost_user_iotlb_wr_lock(vq);
+
+       vq->access_ok = 0;
+       vq->desc = NULL;
+       vq->avail = NULL;
+       vq->used = NULL;
+
+       if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
+               vhost_user_iotlb_wr_unlock(vq);
+}
+
 static void
 init_vring_queue(struct virtio_net *dev, uint32_t vring_idx)
 {
index 6b745aa..b633aba 100644 (file)
@@ -380,6 +380,7 @@ void vhost_backend_cleanup(struct virtio_net *dev);
 uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
                        uint64_t iova, uint64_t size, uint8_t perm);
 int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq);
+void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq);
 
 static __rte_always_inline uint64_t
 vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
index 1e73974..f63258c 100644 (file)
@@ -391,11 +391,7 @@ vhost_user_set_vring_addr(struct virtio_net *dev, VhostUserMsg *msg)
         */
        memcpy(&vq->ring_addrs, addr, sizeof(*addr));
 
-       vq->desc = NULL;
-       vq->avail = NULL;
-       vq->used = NULL;
-
-       vq->access_ok = 0;
+       vring_invalidate(dev, vq);
 
        return 0;
 }
@@ -1011,6 +1007,35 @@ is_vring_iotlb_update(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg)
        return 0;
 }
 
+static int
+is_vring_iotlb_invalidate(struct vhost_virtqueue *vq,
+                               struct vhost_iotlb_msg *imsg)
+{
+       uint64_t istart, iend, vstart, vend;
+
+       istart = imsg->iova;
+       iend = istart + imsg->size - 1;
+
+       vstart = (uintptr_t)vq->desc;
+       vend = vstart + sizeof(struct vring_desc) * vq->size - 1;
+       if (vstart <= iend && istart <= vend)
+               return 1;
+
+       vstart = (uintptr_t)vq->avail;
+       vend = vstart + sizeof(struct vring_avail);
+       vend += sizeof(uint16_t) * vq->size - 1;
+       if (vstart <= iend && istart <= vend)
+               return 1;
+
+       vstart = (uintptr_t)vq->used;
+       vend = vstart + sizeof(struct vring_used);
+       vend += sizeof(struct vring_used_elem) * vq->size - 1;
+       if (vstart <= iend && istart <= vend)
+               return 1;
+
+       return 0;
+}
+
 static int
 vhost_user_iotlb_msg(struct virtio_net **pdev, struct VhostUserMsg *msg)
 {
@@ -1041,6 +1066,9 @@ vhost_user_iotlb_msg(struct virtio_net **pdev, struct VhostUserMsg *msg)
 
                        vhost_user_iotlb_cache_remove(vq, imsg->iova,
                                        imsg->size);
+
+                       if (is_vring_iotlb_invalidate(vq, imsg))
+                               vring_invalidate(dev, vq);
                }
                break;
        default: