From 5a14d0e2e0e0a71b133a7be54bb86c481070cd79 Mon Sep 17 00:00:00 2001 From: Saravanan D Date: Sat, 18 Apr 2026 15:40:01 -0700 Subject: [PATCH] vmm: clear VFIO MMIO regions in DeviceManager::drop DeviceManager and VfioPciDevice both hold Arc for each VFIO BAR mmap window. During VM shutdown, VfioPciDevice drops after DeviceManager::Drop::drop (via device_tree field drop). Without clearing DeviceManager's clones first, VfioPciDevice::unmap_mmio_regions decrements the Arc but does not reach zero, munmap never fires, the VFIO device file VMAs survive, and VFIO_GROUP_UNSET_CONTAINER returns EBUSY. Clear DeviceManager's mmio_regions in Drop::drop so VfioPciDevice is the sole Arc owner at drop time and ensure VFIO_GROUP_UNSET_CONTAINER ioctl success. Remove redundant .clone() on the mmio_regions() return value in the eject_device() hot-unplug path. Add detail comments Signed-off-by: Saravanan D --- vmm/src/device_manager.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 0a263e7c4..e89239132 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -4958,7 +4958,7 @@ impl DeviceManager { // rather than MmioRegion start addresses because move_bar() // updates the device's region addresses but not the // DeviceManager's cloned copies. - let device_regions = vfio_pci_device.lock().unwrap().mmio_regions().clone(); + let device_regions = vfio_pci_device.lock().unwrap().mmio_regions(); let mut mmio_regions = self.mmio_regions.lock().unwrap(); for device_region in &device_regions { mmio_regions.retain(|x| !x.has_matching_slots(device_region)); @@ -5865,6 +5865,11 @@ impl BusDevice for DeviceManager { impl Drop for DeviceManager { fn drop(&mut self) { + // Explicitly clear the regions owned by this device to ensure + // that they are dropped and unmapped before the container is cleared. + // See eject_device() for the device hot-unplug equivalent. + self.mmio_regions.lock().unwrap().clear(); + // Wake up the DeviceManager threads (mainly virtio device workers), // to avoid deadlock on waiting for paused/parked worker threads. if let Err(e) = self.resume() {