|
|
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 |
|