From bc5363823a2e85a25f34cb8653361b6c0ff3381a Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Tue, 28 Apr 2026 03:48:43 +0000 Subject: [PATCH] vmm: DeviceConfig: Store path as Option Relax DeviceConfig::path from PathBuf to Option in preparation to accept an externally-opened vfio cdev FD. The parser and OpenAPI spec still enforces that `path` is set, so callers see no behavior change. Signed-off-by: Bo Chen Assisted-by: Claude:Opus-4.7 --- vmm/src/config.rs | 18 ++++++++++-------- vmm/src/device_manager.rs | 12 ++++++++---- vmm/src/vm_config.rs | 9 +++++++-- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index b625125a5..17d67d6f9 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -2442,7 +2442,7 @@ impl DeviceConfig { .unwrap_or_default(); Ok(DeviceConfig { pci_common, - path, + path: Some(path), x_nv_gpudirect_clique, x_exclude_mmap_bars, }) @@ -3312,9 +3312,11 @@ impl VmConfig { if let Some(devices) = &self.devices { let mut device_paths = BTreeSet::new(); for device in devices { - if !device_paths.insert(device.path.to_string_lossy()) { + if let Some(path) = device.path.as_deref() + && !device_paths.insert(path.to_string_lossy()) + { return Err(ValidationError::DuplicateDevicePath( - device.path.to_string_lossy().to_string(), + path.to_string_lossy().to_string(), )); } @@ -4719,7 +4721,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" fn device_fixture() -> DeviceConfig { DeviceConfig { pci_common: PciDeviceCommonConfig::default(), - path: PathBuf::from("/path/to/device"), + path: Some(PathBuf::from("/path/to/device")), x_nv_gpudirect_clique: None, x_exclude_mmap_bars: Vec::new(), } @@ -6073,11 +6075,11 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.devices = Some(vec![ DeviceConfig { - path: "/device1".into(), + path: Some("/device1".into()), ..device_fixture() }, DeviceConfig { - path: "/device2".into(), + path: Some("/device2".into()), ..device_fixture() }, ]); @@ -6086,11 +6088,11 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.devices = Some(vec![ DeviceConfig { - path: "/device1".into(), + path: Some("/device1".into()), ..device_fixture() }, DeviceConfig { - path: "/device1".into(), + path: Some("/device1".into()), ..device_fixture() }, ]); diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index ce8b699c5..1dcf865c0 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -3976,9 +3976,13 @@ impl DeviceManager { vfio_ops }; - let vfio_device = - VfioDevice::new(&device_cfg.path, Arc::clone(&vfio_ops) as Arc) - .map_err(DeviceManagerError::VfioCreate)?; + // The CLI parser and OpenAPI spec enforce that `path` is set + let device_path = device_cfg + .path + .as_deref() + .expect("DeviceConfig::parse enforces a path"); + let vfio_device = VfioDevice::new(device_path, Arc::clone(&vfio_ops) as Arc) + .map_err(DeviceManagerError::VfioCreate)?; if needs_dma_mapping { // Register DMA mapping in IOMMU. @@ -4063,7 +4067,7 @@ impl DeviceManager { .iter() .map(|bar| *bar as u8) .collect(), - device_cfg.path.clone(), + device_path.to_path_buf(), ) .map_err(DeviceManagerError::VfioPciCreate)?; diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index a08f61c20..5561966d6 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -758,7 +758,8 @@ impl ApplyLandlock for DebugConsoleConfig { pub struct DeviceConfig { #[serde(flatten)] pub pci_common: PciDeviceCommonConfig, - pub path: PathBuf, + #[serde(default)] + pub path: Option, #[serde(default)] pub x_nv_gpudirect_clique: Option, #[serde(default)] @@ -767,7 +768,11 @@ pub struct DeviceConfig { impl ApplyLandlock for DeviceConfig { fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> { - let device_path = fs::read_link(self.path.as_path()).map_err(LandlockError::OpenPath)?; + let path = self + .path + .as_deref() + .expect("DeviceConfig::parse and OpenAPI spec enforce a path"); + let device_path = fs::read_link(path).map_err(LandlockError::OpenPath)?; let iommu_group = device_path.file_name(); let iommu_group_str = iommu_group .ok_or(LandlockError::InvalidPath)?