@@ -172,6 +172,10 @@ int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t ioas_id, hwaddr iova,
.length = size,
};
+ if (be->reused) {
+ return 0;
+ }
+
if (!readonly) {
map.flags |= IOMMU_IOAS_MAP_WRITEABLE;
}
@@ -203,6 +207,10 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
.length = size,
};
+ if (be->reused) {
+ return 0;
+ }
+
ret = ioctl(fd, IOMMU_IOAS_UNMAP, &unmap);
/*
* IOMMUFD takes mapping as some kind of object, unmapping
@@ -27,12 +27,36 @@ static bool vfio_can_cpr_exec(VFIOIOMMUFDContainer *container, Error **errp)
return true;
}
+static int vfio_container_post_load(void *opaque, int version_id)
+{
+ VFIOIOMMUFDContainer *container = opaque;
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+ VFIODevice *vbasedev;
+ Error *err = NULL;
+ uint32_t ioas_id = container->ioas_id;
+
+ if (!iommufd_cdev_get_info_iova_range(container, ioas_id, &err)) {
+ error_report_err(err);
+ return -1;
+ }
+
+ bcontainer->reused = false;
+ QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ vbasedev->reused = false;
+ }
+ container->be->reused = false;
+
+ return 0;
+}
+
static const VMStateDescription vfio_container_vmstate = {
.name = "vfio-iommufd-container",
.version_id = 0,
.minimum_version_id = 0,
+ .post_load = vfio_container_post_load,
.needed = cpr_needed_for_reuse,
.fields = (VMStateField[]) {
+ VMSTATE_UINT32(ioas_id, VFIOIOMMUFDContainer),
VMSTATE_END_OF_LIST()
}
};
@@ -357,6 +357,11 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
}
}
+ if (vbasedev->reused) {
+ ioas_id = -1; /* ioas_id will be sent in vmstate */
+ goto skip_ioas_alloc;
+ }
+
/* Need to allocate a new dedicated container */
if (!iommufd_backend_alloc_ioas(vbasedev->iommufd, &ioas_id, errp)) {
goto err_alloc_ioas;
@@ -364,6 +369,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
trace_iommufd_cdev_alloc_ioas(vbasedev->iommufd->fd, ioas_id);
+skip_ioas_alloc:
container = VFIO_IOMMU_IOMMUFD(object_new(TYPE_VFIO_IOMMU_IOMMUFD));
container->be = vbasedev->iommufd;
container->ioas_id = ioas_id;
@@ -371,7 +377,8 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
bcontainer = &container->bcontainer;
vfio_address_space_insert(space, bcontainer);
- if (!iommufd_cdev_attach_container(vbasedev, container, errp)) {
+ if (!vbasedev->reused &&
+ !iommufd_cdev_attach_container(vbasedev, container, errp)) {
goto err_attach_container;
}
@@ -380,6 +387,10 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
goto err_discard_disable;
}
+ if (vbasedev->reused) {
+ goto skip_info;
+ }
+
if (!iommufd_cdev_get_info_iova_range(container, ioas_id, &err)) {
error_append_hint(&err,
"Fallback to default 64bit IOVA range and 4K page size\n");
@@ -388,6 +399,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
bcontainer->pgsizes = qemu_real_host_page_size();
}
+skip_info:
bcontainer->listener = vfio_memory_listener;
memory_listener_register(&bcontainer->listener, bcontainer->space->as);
Rebuild userland device state after CPR. During vfio_realize, skip all ioctls that configure the device, as it was already configured in old QEMU, and we preserved the device descriptor. Preserve the ioas_id in vmstate. Because we skip ioctl's, it is not needed at realize time. However, we do need to gather range info, so defer the call to iommufd_cdev_get_info_iova_range to a post_load handler, at which time the ioas_id is known. Registering the vfio_memory_listener causes spurious calls to map and unmap DMA, as devices are created and the address space is built. This memory was already already mapped by the device, so suppress map and unmap during CPR -- eg, if the reused flag is set. Clear the reused flag in the post_load handler. Signed-off-by: Steve Sistare <steven.sistare@oracle.com> --- backends/iommufd.c | 8 ++++++++ hw/vfio/cpr-iommufd.c | 24 ++++++++++++++++++++++++ hw/vfio/iommufd.c | 14 +++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-)