summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCédric Le Goater <clg@redhat.com>2025-08-14 17:34:19 +0200
committerCédric Le Goater <clg@redhat.com>2025-09-08 16:46:31 +0200
commitceb59c1cc61dee57c8806571e7c723e555914547 (patch)
tree7492d2c891bcfd19283a9334463f1432c6581d31
parent36cd81dc139f899127d868ba9baaf3079c336efc (diff)
downloadfocaccia-qemu-ceb59c1cc61dee57c8806571e7c723e555914547.tar.gz
focaccia-qemu-ceb59c1cc61dee57c8806571e7c723e555914547.zip
vfio: Report an error when the 'dma_max_mappings' limit is reached
The VFIO IOMMU Type1 kernel driver enforces a default IOMMU mapping
limit of 65535, which is configurable via the 'dma_max_mappings'
module parameter. When this limit is reached, QEMU issues a warning
and fails the mapping operation, but allows the VM to continue
running, potentially causing issues later. This scenario occurs with
SEV-SNP guests, which must update all IOMMU mappings during
initialization.

To address this, update vfio_ram_discard_register_listener() to accept
an 'Error **' parameter and propagate the error to the caller. This
change will halt the VM immediately, at init time, with the same error
message.

Additionally, the same behavior will be enforced at runtime. While
this might be considered too brutal, the rarity of this case and the
planned removal of the dma_max_mappings module parameter make it a
reasonable approach.

Cc: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20250814153419.1643897-1-clg@redhat.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
-rw-r--r--hw/vfio/listener.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c
index 5ebafaa07e..c244be5e21 100644
--- a/hw/vfio/listener.c
+++ b/hw/vfio/listener.c
@@ -250,8 +250,9 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
     return 0;
 }
 
-static void vfio_ram_discard_register_listener(VFIOContainerBase *bcontainer,
-                                               MemoryRegionSection *section)
+static bool vfio_ram_discard_register_listener(VFIOContainerBase *bcontainer,
+                                               MemoryRegionSection *section,
+                                               Error **errp)
 {
     RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr);
     int target_page_size = qemu_target_page_size();
@@ -316,13 +317,15 @@ static void vfio_ram_discard_register_listener(VFIOContainerBase *bcontainer,
 
         if (vrdl_mappings + max_memslots - vrdl_count >
             bcontainer->dma_max_mappings) {
-            warn_report("%s: possibly running out of DMA mappings. E.g., try"
+            error_setg(errp, "%s: possibly running out of DMA mappings. E.g., try"
                         " increasing the 'block-size' of virtio-mem devies."
                         " Maximum possible DMA mappings: %d, Maximum possible"
                         " memslots: %d", __func__, bcontainer->dma_max_mappings,
                         max_memslots);
+            return false;
         }
     }
+    return true;
 }
 
 static void vfio_ram_discard_unregister_listener(VFIOContainerBase *bcontainer,
@@ -571,7 +574,9 @@ void vfio_container_region_add(VFIOContainerBase *bcontainer,
      */
     if (memory_region_has_ram_discard_manager(section->mr)) {
         if (!cpr_remap) {
-            vfio_ram_discard_register_listener(bcontainer, section);
+            if (!vfio_ram_discard_register_listener(bcontainer, section, &err)) {
+                goto fail;
+            }
         } else if (!vfio_cpr_ram_discard_register_listener(bcontainer,
                                                            section)) {
             error_setg(&err,