mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: release vIOMMU VFIO container on device eject
Currently ejecting a device leaks its mapping keeping the container fd open. Remove the mapping so the fd can be closed. Assisted-by: Claude:Opus-4.8 Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
@@ -1244,6 +1244,14 @@ impl Iommu {
|
|||||||
self.ext_mapping.lock().unwrap().insert(device_id, mapping);
|
self.ext_mapping.lock().unwrap().insert(device_id, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a mapping added with `add_external_mapping`.
|
||||||
|
pub fn remove_external_mapping(
|
||||||
|
&mut self,
|
||||||
|
device_id: u32,
|
||||||
|
) -> Option<Arc<dyn ExternalDmaMapping>> {
|
||||||
|
self.ext_mapping.lock().unwrap().remove(&device_id)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(fuzzing)]
|
#[cfg(fuzzing)]
|
||||||
pub fn wait_for_epoll_threads(&mut self) {
|
pub fn wait_for_epoll_threads(&mut self) {
|
||||||
self.common.wait_for_epoll_threads();
|
self.common.wait_for_epoll_threads();
|
||||||
@@ -1362,3 +1370,73 @@ impl Snapshottable for Iommu {
|
|||||||
}
|
}
|
||||||
impl Transportable for Iommu {}
|
impl Transportable for Iommu {}
|
||||||
impl Migratable for Iommu {}
|
impl Migratable for Iommu {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
|
use seccompiler::SeccompAction;
|
||||||
|
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||||
|
use vmm_sys_util::eventfd::{EFD_NONBLOCK, EventFd};
|
||||||
|
|
||||||
|
use super::Iommu;
|
||||||
|
|
||||||
|
/// Test stub for VfioDmaMapping.
|
||||||
|
struct MockMapping;
|
||||||
|
|
||||||
|
impl ExternalDmaMapping for MockMapping {
|
||||||
|
fn map(&self, _iova: u64, _gpa: u64, _size: u64) -> Result<(), io::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, _iova: u64, _size: u64) -> Result<(), io::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_iommu() -> Iommu {
|
||||||
|
let (iommu, _mapping) = Iommu::new(
|
||||||
|
"test-iommu".to_string(),
|
||||||
|
SeccompAction::Allow,
|
||||||
|
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||||
|
(0, 0),
|
||||||
|
64,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
iommu
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tests removing a mapping works and releases the ref.
|
||||||
|
#[test]
|
||||||
|
fn remove_external_mapping() {
|
||||||
|
let mut iommu = new_iommu();
|
||||||
|
|
||||||
|
let mapping: Arc<dyn ExternalDmaMapping> = Arc::new(MockMapping);
|
||||||
|
let weak: Weak<dyn ExternalDmaMapping> = Arc::downgrade(&mapping);
|
||||||
|
|
||||||
|
iommu.add_external_mapping(0x100, mapping);
|
||||||
|
|
||||||
|
// Removing the mapping succeeds.
|
||||||
|
let removed = iommu.remove_external_mapping(0x100);
|
||||||
|
assert!(removed.is_some());
|
||||||
|
|
||||||
|
// Dropping the returned Arc drops the last reference.
|
||||||
|
drop(removed);
|
||||||
|
assert!(
|
||||||
|
weak.upgrade().is_none(),
|
||||||
|
"iommu must not retain a reference after removal"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Removing the same id again is a nop.
|
||||||
|
assert!(
|
||||||
|
iommu.remove_external_mapping(0x100).is_none(),
|
||||||
|
"removal is idempotent"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Removing a bogus ID doesn't crash.
|
||||||
|
assert!(iommu.remove_external_mapping(0x999).is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5020,6 +5020,13 @@ impl DeviceManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(iommu) = &self.iommu_device {
|
||||||
|
iommu
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.remove_external_mapping(pci_device_bdf.into());
|
||||||
|
}
|
||||||
|
|
||||||
if remove_dma_handler {
|
if remove_dma_handler {
|
||||||
for virtio_mem_device in self.virtio_mem_devices.iter() {
|
for virtio_mem_device in self.virtio_mem_devices.iter() {
|
||||||
let source = VirtioMemMappingSource::Device(pci_device_bdf.into());
|
let source = VirtioMemMappingSource::Device(pci_device_bdf.into());
|
||||||
|
|||||||
Reference in New Issue
Block a user