thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch

ed5979
From 55aad90e347599e88747888ddbefcba33427f386 Mon Sep 17 00:00:00 2001
ed5979
From: Jason Wang <jasowang@redhat.com>
ed5979
Date: Fri, 16 Dec 2022 11:35:52 +0800
ed5979
Subject: [PATCH 12/31] vhost: fix vq dirty bitmap syncing when vIOMMU is
ed5979
 enabled
ed5979
ed5979
RH-Author: Eric Auger <eric.auger@redhat.com>
ed5979
RH-MergeRequest: 134: vhost: fix vq dirty bitmap syncing when vIOMMU is enabled
ed5979
RH-Bugzilla: 2124856
ed5979
RH-Acked-by: Peter Xu <peterx@redhat.com>
ed5979
RH-Acked-by: Jason Wang <jasowang@redhat.com>
ed5979
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
ed5979
RH-Commit: [1/1] 57ef499b63dc2cca6e64ee84d1dc127635868ca2 (eauger1/centos-qemu-kvm)
ed5979
ed5979
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2124856
ed5979
Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=49989924
ed5979
Upstream: yes
ed5979
ed5979
When vIOMMU is enabled, the vq->used_phys is actually the IOVA not
ed5979
GPA. So we need to translate it to GPA before the syncing otherwise we
ed5979
may hit the following crash since IOVA could be out of the scope of
ed5979
the GPA log size. This could be noted when using virtio-IOMMU with
ed5979
vhost using 1G memory.
ed5979
ed5979
Fixes: c471ad0e9bd46 ("vhost_net: device IOTLB support")
ed5979
Cc: qemu-stable@nongnu.org
ed5979
Tested-by: Lei Yang <leiyang@redhat.com>
ed5979
Reported-by: Yalan Zhang <yalzhang@redhat.com>
ed5979
Signed-off-by: Jason Wang <jasowang@redhat.com>
ed5979
Message-Id: <20221216033552.77087-1-jasowang@redhat.com>
ed5979
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
ed5979
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
ed5979
(cherry picked from commit 345cc1cbcbce2bab00abc2b88338d7d89c702d6b)
ed5979
Signed-off-by: Eric Auger <eric.auger@redhat.com>
ed5979
---
ed5979
 hw/virtio/vhost.c | 84 ++++++++++++++++++++++++++++++++++++-----------
ed5979
 1 file changed, 64 insertions(+), 20 deletions(-)
ed5979
ed5979
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
ed5979
index 84dbb39e07..2c566dc539 100644
ed5979
--- a/hw/virtio/vhost.c
ed5979
+++ b/hw/virtio/vhost.c
ed5979
@@ -20,6 +20,7 @@
ed5979
 #include "qemu/range.h"
ed5979
 #include "qemu/error-report.h"
ed5979
 #include "qemu/memfd.h"
ed5979
+#include "qemu/log.h"
ed5979
 #include "standard-headers/linux/vhost_types.h"
ed5979
 #include "hw/virtio/virtio-bus.h"
ed5979
 #include "hw/virtio/virtio-access.h"
ed5979
@@ -106,6 +107,24 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
ed5979
     }
ed5979
 }
ed5979
 
ed5979
+static bool vhost_dev_has_iommu(struct vhost_dev *dev)
ed5979
+{
ed5979
+    VirtIODevice *vdev = dev->vdev;
ed5979
+
ed5979
+    /*
ed5979
+     * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support
ed5979
+     * incremental memory mapping API via IOTLB API. For platform that
ed5979
+     * does not have IOMMU, there's no need to enable this feature
ed5979
+     * which may cause unnecessary IOTLB miss/update transactions.
ed5979
+     */
ed5979
+    if (vdev) {
ed5979
+        return virtio_bus_device_iommu_enabled(vdev) &&
ed5979
+            virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
ed5979
+    } else {
ed5979
+        return false;
ed5979
+    }
ed5979
+}
ed5979
+
ed5979
 static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
ed5979
                                    MemoryRegionSection *section,
ed5979
                                    hwaddr first,
ed5979
@@ -137,8 +156,51 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
ed5979
             continue;
ed5979
         }
ed5979
 
ed5979
-        vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys,
ed5979
-                              range_get_last(vq->used_phys, vq->used_size));
ed5979
+        if (vhost_dev_has_iommu(dev)) {
ed5979
+            IOMMUTLBEntry iotlb;
ed5979
+            hwaddr used_phys = vq->used_phys, used_size = vq->used_size;
ed5979
+            hwaddr phys, s, offset;
ed5979
+
ed5979
+            while (used_size) {
ed5979
+                rcu_read_lock();
ed5979
+                iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as,
ed5979
+                                                      used_phys,
ed5979
+                                                      true,
ed5979
+                                                      MEMTXATTRS_UNSPECIFIED);
ed5979
+                rcu_read_unlock();
ed5979
+
ed5979
+                if (!iotlb.target_as) {
ed5979
+                    qemu_log_mask(LOG_GUEST_ERROR, "translation "
ed5979
+                                  "failure for used_iova %"PRIx64"\n",
ed5979
+                                  used_phys);
ed5979
+                    return -EINVAL;
ed5979
+                }
ed5979
+
ed5979
+                offset = used_phys & iotlb.addr_mask;
ed5979
+                phys = iotlb.translated_addr + offset;
ed5979
+
ed5979
+                /*
ed5979
+                 * Distance from start of used ring until last byte of
ed5979
+                 * IOMMU page.
ed5979
+                 */
ed5979
+                s = iotlb.addr_mask - offset;
ed5979
+                /*
ed5979
+                 * Size of used ring, or of the part of it until end
ed5979
+                 * of IOMMU page. To avoid zero result, do the adding
ed5979
+                 * outside of MIN().
ed5979
+                 */
ed5979
+                s = MIN(s, used_size - 1) + 1;
ed5979
+
ed5979
+                vhost_dev_sync_region(dev, section, start_addr, end_addr, phys,
ed5979
+                                      range_get_last(phys, s));
ed5979
+                used_size -= s;
ed5979
+                used_phys += s;
ed5979
+            }
ed5979
+        } else {
ed5979
+            vhost_dev_sync_region(dev, section, start_addr,
ed5979
+                                  end_addr, vq->used_phys,
ed5979
+                                  range_get_last(vq->used_phys, vq->used_size));
ed5979
+        }
ed5979
     }
ed5979
     return 0;
ed5979
 }
ed5979
@@ -306,24 +368,6 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
ed5979
     dev->log_size = size;
ed5979
 }
ed5979
 
ed5979
-static bool vhost_dev_has_iommu(struct vhost_dev *dev)
ed5979
-{
ed5979
-    VirtIODevice *vdev = dev->vdev;
ed5979
-
ed5979
-    /*
ed5979
-     * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support
ed5979
-     * incremental memory mapping API via IOTLB API. For platform that
ed5979
-     * does not have IOMMU, there's no need to enable this feature
ed5979
-     * which may cause unnecessary IOTLB miss/update transactions.
ed5979
-     */
ed5979
-    if (vdev) {
ed5979
-        return virtio_bus_device_iommu_enabled(vdev) &&
ed5979
-            virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
ed5979
-    } else {
ed5979
-        return false;
ed5979
-    }
ed5979
-}
ed5979
-
ed5979
 static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr,
ed5979
                               hwaddr *plen, bool is_write)
ed5979
 {
ed5979
-- 
ed5979
2.31.1
ed5979