@samitouri / QOSamiQemu / commits / 27b28632d0

vfio/listener: Fix translated_addr for non-identity-mapped RAM sections

In vfio_listener_region_del(), when dirty tracking is active and a writable RAM section is deleted, a synthetic IOMMUTLBEntry is built to flush dirty pages. Setting translated_addr to the IOVA (GPA) is only correct for identity-mapped regions where GPA == ram_addr_t. For RAM sections with GPA far above main RAM (e.g., nested VT-d interrupt remapping table at 58 TB), translated_addr is too large, causing a crash in physical_memory_set_dirty_lebitmap() when indexing beyond the allocated dirty memory blocks array : bitmap_set_atomic(map=NULL, start=1, nr=1) physical_memory_set_dirty_range(start=0x380004040000, length=4096) physical_memory_set_dirty_lebitmap(start=0x380004040000, pages=3) vfio_container_query_dirty_bitmap(translated_addr=0x380004040000) vfio_legacy_dma_unmap_one(iova=0x380004040000, size=12288) vfio_listener_region_del() Fix this by setting translated_addr to the ram_addr_t of the section, which is consistent with other vfio dirty tracking code: translated_addr = memory_region_get_ram_addr(section->mr) + section->offset_within_region; Cc: Zhenzhong Duan <zhenzhong.duan@intel.com> Fixes: 6e360c06176c ("vfio/listener: Add missing dirty tracking in region_del") Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Tested-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/20260625134352.3122572-1-clg@redhat.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Cédric Le Goater committed Jun 25, 2026 at 15:43 UTC 27b28632d0dbe9b74e5a725334dd0e6d03919b69
1 file changed +3 -2
hw/vfio/listener.c
+3 -2
@@ -731,7 +731,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
731 }
732
733 /*
734 - * Fake an IOTLB entry for writable identity mapping which is needed
734 + * Fake an IOTLB entry for writable RAM sections which is needed
735 * by dirty tracking when switch out of PT domain. In fact, in
736 * unmap_bitmap, only translated_addr field is used to set dirty
737 * bitmap.
@@ -746,7 +746,8 @@ static void vfio_listener_region_del(MemoryListener *listener,
746 if (global_dirty_tracking && memory_region_is_ram(section->mr) &&
747 !section->readonly) {
748 entry.iova = iova;
749 - entry.translated_addr = iova;
749 + entry.translated_addr = memory_region_get_ram_addr(section->mr) +
750 + section->offset_within_region;
751 iotlb = &entry;
752 }
753