Re: [PATCH V1 07/26] vfio/container: recover from unmap-all-vaddr failure
On 2/4/2025 9:10 AM, Cédric Le Goater wrote:
On 1/29/25 15:43, Steve Sistare wrote:
If there are multiple containers and unmap-all fails for some container, we
need to remap vaddr for the other containers for which unmap-all succeeded.
Recover by walking all address ranges of all containers to restore the vaddr
for each. Do so by invoking the vfio listener callback, and passing a new
"remap" flag that tells it to restore a mapping without re-allocating new
userland data structures.
Signed-off-by: Steve Sistare
---
hw/vfio/common.c | 47 ++-
hw/vfio/cpr-legacy.c | 44
include/hw/vfio/vfio-common.h | 6 +-
3 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7370332..c8ee71a 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -580,6 +580,13 @@ static void vfio_listener_region_add(MemoryListener
*listener,
{
VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
listener);
+ vfio_container_region_add(bcontainer, section, false);
+}
+
+void vfio_container_region_add(VFIOContainerBase *bcontainer,
+ MemoryRegionSection *section,
+ bool remap)
+{
vfio_container_region_add() is already complex enough. Please consider
doing an initial refactoring before adding a new code path. It would be
welcome !
I'll take a look after factoring out the cpr code into helpers as you
request below.
hwaddr iova, end;
Int128 llend, llsize;
void *vaddr;
@@ -614,6 +621,30 @@ static void vfio_listener_region_add(MemoryListener
*listener,
int iommu_idx;
trace_vfio_listener_region_add_iommu(section->mr->name, iova, end);
+
+ /*
+ * If remap, then VFIO_DMA_UNMAP_FLAG_VADDR has been called, and we
+ * want to remap the vaddr. vfio_container_region_add was already
+ * called in the past, so the giommu already exists. Find it and
+ * replay it, which calls vfio_dma_map further down the stack.
+ */
+
+ if (remap) {
+ hwaddr as_offset = section->offset_within_address_space;
+ hwaddr iommu_offset = as_offset - section->offset_within_region;
+
+ QLIST_FOREACH(giommu, &bcontainer->giommu_list, giommu_next) {
+ if (giommu->iommu_mr == iommu_mr &&
+ giommu->iommu_offset == iommu_offset) {
+ memory_region_iommu_replay(giommu->iommu_mr, &giommu->n);
+ return;
+ }
+ }
+ error_report("Container cannot find iommu region %s offset %lx",
+ memory_region_name(section->mr), iommu_offset);
error_report() are not welcomed. We need to find a way to propagate
this error.
I follow the existing practice in this function, which already reports other
errors. This is called in the context of a memory listener region_add method,
so returning an error affects the signature of all listeners and should be a
seperate RFE.
+ goto fail;
+ }
Please introduce a vfio_cpr helper for the section above and move it
under the hw/vfio/cpr* files.
OK.
/*
* FIXME: For VFIO iommu types which have KVM acceleration to
* avoid bouncing all map/unmaps through qemu this way, this
@@ -656,7 +687,21 @@ static void vfio_listener_region_add(MemoryListener
*listener,
* about changes.
*/
if (memory_region_has_ram_discard_manager(section->mr)) {
- vfio_register_ram_discard_listener(bcontainer, section);
+ /*
+ * If remap, then VFIO_DMA_UNMAP_FLAG_VADDR has been called, and we
+ * want to remap the vaddr. vfio_container_region_add was already
+ * called in the past, so the ram discard listener already exists.
+ * Call its populate function directly, which calls vfio_dma_map.
+ */
+ if (remap) {
+ VFIORamDiscardListener *vrdl =
+ vfio_find_ram_discard_listener(bcontainer, section);
+ if (vrdl->listener.notify_populate(&vrdl->listener, section)) {
+ error_report("listener.notify_populate failed");
+ }
+ } else {
+ vfio_register_ram_discard_listener(bcontainer, section);
+ }
idem.
OK.
return;
}
diff --git a/hw/vfio/cpr-legacy.c b/hw/vfio/cpr-legacy.c
index f3a31d1..3139de1 100644
--- a/hw/vfio/cpr-legacy.c
+++ b/hw/vfio/cpr-legacy.c
@@ -26,9 +26,18 @@ static bool vfio_dma_unmap_vaddr_all(VFIOContainer
*container, Error **errp)
error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all");
return false;
}
+ container->vaddr_unmapped = true;
return true;> }
+static void vfio_region_remap(MemoryListener *listener,
+ MemoryRe
Re: [PATCH V1 07/26] vfio/container: recover from unmap-all-vaddr failure
On 1/29/25 15:43, Steve Sistare wrote:
If there are multiple containers and unmap-all fails for some container, we
need to remap vaddr for the other containers for which unmap-all succeeded.
Recover by walking all address ranges of all containers to restore the vaddr
for each. Do so by invoking the vfio listener callback, and passing a new
"remap" flag that tells it to restore a mapping without re-allocating new
userland data structures.
Signed-off-by: Steve Sistare
---
hw/vfio/common.c | 47 ++-
hw/vfio/cpr-legacy.c | 44
include/hw/vfio/vfio-common.h | 6 +-
3 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7370332..c8ee71a 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -580,6 +580,13 @@ static void vfio_listener_region_add(MemoryListener
*listener,
{
VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
listener);
+vfio_container_region_add(bcontainer, section, false);
+}
+
+void vfio_container_region_add(VFIOContainerBase *bcontainer,
+ MemoryRegionSection *section,
+ bool remap)
+{
vfio_container_region_add() is already complex enough. Please consider
doing an initial refactoring before adding a new code path. It would be
welcome !
hwaddr iova, end;
Int128 llend, llsize;
void *vaddr;
@@ -614,6 +621,30 @@ static void vfio_listener_region_add(MemoryListener
*listener,
int iommu_idx;
trace_vfio_listener_region_add_iommu(section->mr->name, iova, end);
+
+/*
+ * If remap, then VFIO_DMA_UNMAP_FLAG_VADDR has been called, and we
+ * want to remap the vaddr. vfio_container_region_add was already
+ * called in the past, so the giommu already exists. Find it and
+ * replay it, which calls vfio_dma_map further down the stack.
+ */
+
+if (remap) {
+hwaddr as_offset = section->offset_within_address_space;
+hwaddr iommu_offset = as_offset - section->offset_within_region;
+
+QLIST_FOREACH(giommu, &bcontainer->giommu_list, giommu_next) {
+if (giommu->iommu_mr == iommu_mr &&
+giommu->iommu_offset == iommu_offset) {
+memory_region_iommu_replay(giommu->iommu_mr, &giommu->n);
+return;
+}
+}
+error_report("Container cannot find iommu region %s offset %lx",
+memory_region_name(section->mr), iommu_offset);
error_report() are not welcomed. We need to find a way to propagate
this error.
+goto fail;
+}
Please introduce a vfio_cpr helper for the section above and move it
under the hw/vfio/cpr* files.
/*
* FIXME: For VFIO iommu types which have KVM acceleration to
* avoid bouncing all map/unmaps through qemu this way, this
@@ -656,7 +687,21 @@ static void vfio_listener_region_add(MemoryListener
*listener,
* about changes.
*/
if (memory_region_has_ram_discard_manager(section->mr)) {
-vfio_register_ram_discard_listener(bcontainer, section);
+/*
+ * If remap, then VFIO_DMA_UNMAP_FLAG_VADDR has been called, and we
+ * want to remap the vaddr. vfio_container_region_add was already
+ * called in the past, so the ram discard listener already exists.
+ * Call its populate function directly, which calls vfio_dma_map.
+ */
+if (remap) {
+VFIORamDiscardListener *vrdl =
+vfio_find_ram_discard_listener(bcontainer, section);
+if (vrdl->listener.notify_populate(&vrdl->listener, section)) {
+error_report("listener.notify_populate failed");
+}
+} else {
+vfio_register_ram_discard_listener(bcontainer, section);
+}
idem.
return;
}
diff --git a/hw/vfio/cpr-legacy.c b/hw/vfio/cpr-legacy.c
index f3a31d1..3139de1 100644
--- a/hw/vfio/cpr-legacy.c
+++ b/hw/vfio/cpr-legacy.c
@@ -26,9 +26,18 @@ static bool vfio_dma_unmap_vaddr_all(VFIOContainer
*container, Error **errp)
error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all");
return false;
}
+container->vaddr_unmapped = true;
return true;> }
+static void vfio_region_remap(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+VFIOContainer *container = container_of(listener, VFIOContainer,
+remap_listener);
+vfio_container_region_add(&container->bcontainer, section, true);
+}
+
static bool vfio_cpr_supported(VFIOContainer *container, Error **errp)
{
if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR
