vmm: clear VFIO MMIO regions in DeviceManager::drop

DeviceManager and VfioPciDevice both hold Arc<MmapRegion> 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 <saravanand@crusoe.ai>
This commit is contained in:
Saravanan D
2026-04-18 15:40:01 -07:00
committed by Rob Bradford
parent 7294ca99cf
commit 5a14d0e2e0

View File

@@ -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() {