From ba04c4f318f77fd6221b14ef3878dae73cb282aa Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Fri, 15 May 2026 10:26:59 +0200 Subject: [PATCH] virtio-devices, vmm: replace Vec with Box<[T]> in config structs I started by looking at all `Option>` values in config.rs and vm_config.rs, and replaced them with `Option>`. This has the advantage that one now can see at a glance if this field will ever resize during operation or not, reducing cognitive load and increasing maintainability. All fields that need the properties of a Ver or where this change was not trivial are kept intact. On-behalf-of: SAP philipp.schuster@sap.com Signed-off-by: Philipp Schuster --- virtio-devices/src/block.rs | 14 ++-- vmm/src/config.rs | 142 ++++++++++++++++++------------------ vmm/src/vm_config.rs | 24 +++--- 3 files changed, 93 insertions(+), 87 deletions(-) diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index 6946924f3..f40f1a49a 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -155,7 +155,7 @@ struct BlockEpollHandler { disk_image: Box, disk_nsectors: Arc, interrupt_cb: Arc, - serial: Vec, + serial: Box<[u8]>, kill_evt: EventFd, pause_evt: EventFd, writeback: Arc, @@ -164,7 +164,7 @@ struct BlockEpollHandler { inflight_requests: VecDeque<(u16, Request)>, rate_limiter: Option, access_platform: Option>, - host_cpus: Option>, + host_cpus: Option>, acked_features: u64, disable_sector0_writes: bool, } @@ -723,8 +723,8 @@ pub struct Block { seccomp_action: SeccompAction, rate_limiter: Option>, exit_evt: EventFd, - serial: Vec, - queue_affinity: BTreeMap>, + serial: Box<[u8]>, + queue_affinity: BTreeMap>, disable_sector0_writes: bool, lock_granularity_choice: LockGranularityChoice, device_status: Arc, @@ -755,7 +755,7 @@ impl Block { rate_limiter: Option>, exit_evt: EventFd, state: Option, - queue_affinity: BTreeMap>, + queue_affinity: BTreeMap>, sparse: bool, disable_sector0_writes: bool, lock_granularity: LockGranularityChoice, @@ -862,7 +862,9 @@ impl Block { (disk_nsectors, avail_features, 0, config, false) }; - let serial = serial.map_or_else(|| build_serial(&disk_path), Vec::from); + let serial = serial + .map_or_else(|| build_serial(&disk_path), Vec::from) + .into_boxed_slice(); Ok(Block { common: VirtioCommon { diff --git a/vmm/src/config.rs b/vmm/src/config.rs index ca697c5e3..71d903d01 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -889,7 +889,7 @@ impl PlatformConfig { let oem_strings = parser .convert::("oem_strings") .map_err(Error::ParsePlatform)? - .map(|v| v.0); + .map(|v| v.0.into_boxed_slice()); let iommufd = parser .convert::("iommufd") .map_err(Error::ParsePlatform)? @@ -1390,7 +1390,7 @@ impl DiskConfig { v.0.iter() .map(|(e1, e2)| VirtQueueAffinity { queue_index: *e1, - host_cpus: e2.clone(), + host_cpus: e2.clone().into_boxed_slice(), }) .collect() }); @@ -2469,7 +2469,7 @@ impl NumaConfig { let memory_zones = parser .convert::("memory_zones") .map_err(Error::ParseNuma)? - .map(|v| v.0); + .map(|v| v.0.into_boxed_slice()); let pci_segments = parser .convert::("pci_segments") .map_err(Error::ParseNuma)? @@ -3250,14 +3250,14 @@ impl VmConfig { } pub fn parse(vm_params: VmParams) -> Result { - let mut rate_limit_groups: Option> = None; + let mut rate_limit_groups: Option> = None; if let Some(rate_limit_group_list) = &vm_params.rate_limit_groups { let mut rate_limit_group_config_list = Vec::new(); for item in rate_limit_group_list.iter() { let rate_limit_group_config = RateLimiterGroupConfig::parse(item)?; rate_limit_group_config_list.push(rate_limit_group_config); } - rate_limit_groups = Some(rate_limit_group_config_list); + rate_limit_groups = Some(rate_limit_group_config_list.into_boxed_slice()); } let mut disks: Option> = None; @@ -3369,26 +3369,26 @@ impl VmConfig { vsock = Some(vsock_config); } - let mut pci_segments: Option> = None; + let mut pci_segments: Option> = None; if let Some(pci_segment_list) = &vm_params.pci_segments { let mut pci_segment_config_list = Vec::new(); for item in pci_segment_list.iter() { let pci_segment_config = PciSegmentConfig::parse(item)?; pci_segment_config_list.push(pci_segment_config); } - pci_segments = Some(pci_segment_config_list); + pci_segments = Some(pci_segment_config_list.into_boxed_slice()); } let platform = vm_params.platform.map(PlatformConfig::parse).transpose()?; - let mut numa: Option> = None; + let mut numa: Option> = None; if let Some(numa_list) = &vm_params.numa { let mut numa_config_list = Vec::new(); for item in numa_list.iter() { let numa_config = NumaConfig::parse(item)?; numa_config_list.push(numa_config); } - numa = Some(numa_config_list); + numa = Some(numa_config_list.into_boxed_slice()); } #[cfg(not(feature = "igvm"))] @@ -3426,13 +3426,14 @@ impl VmConfig { #[cfg(feature = "guest_debug")] let gdb = vm_params.gdb; - let mut landlock_rules: Option> = None; + let mut landlock_rules: Option> = None; if let Some(ll_rules) = vm_params.landlock_rules { landlock_rules = Some( ll_rules .iter() .map(|rule| LandlockConfig::parse(rule)) - .collect::>>()?, + .collect::>>()? + .into_boxed_slice(), ); } @@ -4085,24 +4086,24 @@ mod unit_tests { assert_eq!( DiskConfig::parse("path=/path/to_file,queue_affinity=[0@[1],1@[2],2@[3,4],3@[5-8]]")?, DiskConfig { - queue_affinity: Some(vec![ + queue_affinity: Some(Box::new([ VirtQueueAffinity { queue_index: 0, - host_cpus: vec![1], + host_cpus: Box::new([1]), }, VirtQueueAffinity { queue_index: 1, - host_cpus: vec![2], + host_cpus: Box::new([2]), }, VirtQueueAffinity { queue_index: 2, - host_cpus: vec![3, 4], + host_cpus: Box::new([3, 4]), }, VirtQueueAffinity { queue_index: 3, - host_cpus: vec![5, 6, 7, 8], + host_cpus: Box::new([5, 6, 7, 8]), } - ]), + ])), ..disk_fixture() } ); @@ -4615,14 +4616,14 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" memory_zones=[mem0],pci_segments=[0]"; let expected_standard = NumaConfig { guest_numa_id: 1, - cpus: Some(vec![2, 3]), - distances: Some(vec![NumaDistance { + cpus: Some(Box::new([2, 3])), + distances: Some(Box::new([NumaDistance { destination: 0, distance: 20, - }]), + }])), device_id: None, - memory_zones: Some(vec!["mem0".to_string()]), - pci_segments: Some(vec![0]), + memory_zones: Some(Box::new(["mem0".to_string()])), + pci_segments: Some(Box::new([0])), }; assert_eq!(NumaConfig::parse(standard_input)?, expected_standard); // Successful generic initiator config parse @@ -4630,13 +4631,13 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let expected_gi = NumaConfig { guest_numa_id: 2, cpus: None, - distances: Some(vec![NumaDistance { + distances: Some(Box::new([NumaDistance { destination: 0, distance: 30, - }]), + }])), device_id: Some("vfio1".to_string()), memory_zones: None, - pci_segments: Some(vec![1]), + pci_segments: Some(Box::new([1])), }; assert_eq!(NumaConfig::parse(gi_input)?, expected_gi); Ok(()) @@ -4648,10 +4649,10 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let config = NumaConfig { guest_numa_id: 0, cpus: None, - distances: Some(vec![NumaDistance { + distances: Some(Box::new([NumaDistance { destination: 1, distance: 20, - }]), + }])), memory_zones: None, device_id: Some("vfio0".to_string()), pci_segments: None, @@ -4679,7 +4680,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" // device_id and cpus specified let config = NumaConfig { guest_numa_id: 0, - cpus: Some(vec![0, 1]), + cpus: Some(Box::new([0, 1])), distances: None, device_id: Some("vfio0".to_string()), memory_zones: None, @@ -4696,7 +4697,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" cpus: None, distances: None, device_id: Some("vfio0".to_string()), - memory_zones: Some(vec!["mem0".to_string()]), + memory_zones: Some(Box::new(["mem0".to_string()])), pci_segments: None, }; assert!(config.validate().is_err()); @@ -4707,13 +4708,13 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" // No device_id let config = NumaConfig { guest_numa_id: 0, - cpus: Some(vec![0, 1]), - distances: Some(vec![NumaDistance { + cpus: Some(Box::new([0, 1])), + distances: Some(Box::new([NumaDistance { destination: 1, distance: 20, - }]), + }])), device_id: None, - memory_zones: Some(vec!["mem0".to_string()]), + memory_zones: Some(Box::new(["mem0".to_string()])), pci_segments: None, }; config.validate().unwrap(); @@ -5424,14 +5425,17 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.validate().unwrap(); let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![MAX_NUM_PCI_SEGMENTS + 1, MAX_NUM_PCI_SEGMENTS + 2]), + iommu_segments: Some(Box::new([ + MAX_NUM_PCI_SEGMENTS + 1, + MAX_NUM_PCI_SEGMENTS + 2, + ])), ..platform_fixture() }); assert_eq!( @@ -5453,7 +5457,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.disks = Some(vec![DiskConfig { @@ -5468,7 +5472,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.net = Some(vec![NetConfig { @@ -5483,7 +5487,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.pmem = Some(vec![PmemConfig { @@ -5498,7 +5502,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.devices = Some(vec![DeviceConfig { @@ -5513,7 +5517,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut still_valid_config = valid_config.clone(); still_valid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); still_valid_config.vsock = Some(VsockConfig { @@ -5529,7 +5533,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.disks = Some(vec![DiskConfig { @@ -5547,7 +5551,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.net = Some(vec![NetConfig { @@ -5566,7 +5570,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { num_pci_segments: MAX_NUM_PCI_SEGMENTS, - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.pmem = Some(vec![PmemConfig { @@ -5584,7 +5588,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { num_pci_segments: MAX_NUM_PCI_SEGMENTS, - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.devices = Some(vec![DeviceConfig { @@ -5601,7 +5605,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.vsock = Some(VsockConfig { @@ -5620,7 +5624,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.memory.shared = true; invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.user_devices = Some(vec![UserDeviceConfig { @@ -5637,7 +5641,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.vdpa = Some(vec![VdpaConfig { @@ -5655,7 +5659,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" let mut invalid_config = valid_config.clone(); invalid_config.memory.shared = true; invalid_config.platform = Some(PlatformConfig { - iommu_segments: Some(vec![1, 2, 3]), + iommu_segments: Some(Box::new([1, 2, 3])), ..platform_fixture() }); invalid_config.fs = Some(vec![FsConfig { @@ -5675,81 +5679,81 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" num_pci_segments: 2, ..platform_fixture() }); - invalid_config.numa = Some(vec![ + invalid_config.numa = Some(Box::new([ NumaConfig { guest_numa_id: 0, - cpus: Some(vec![0]), - pci_segments: Some(vec![1]), + cpus: Some(Box::new([0])), + pci_segments: Some(Box::new([1])), ..numa_fixture() }, NumaConfig { guest_numa_id: 1, - cpus: Some(vec![1]), - pci_segments: Some(vec![1]), + cpus: Some(Box::new([1])), + pci_segments: Some(Box::new([1])), ..numa_fixture() }, - ]); + ])); assert_eq!( invalid_config.validate(), Err(ValidationError::PciSegmentReused(1, 0, 1)) ); let mut invalid_config = valid_config.clone(); - invalid_config.pci_segments = Some(vec![PciSegmentConfig { + invalid_config.pci_segments = Some(Box::new([PciSegmentConfig { pci_segment: 0, mmio32_aperture_weight: 1, mmio64_aperture_weight: 0, - }]); + }])); assert_eq!( invalid_config.validate(), Err(ValidationError::InvalidPciSegmentApertureWeight(0)) ); let mut invalid_config = valid_config.clone(); - invalid_config.pci_segments = Some(vec![PciSegmentConfig { + invalid_config.pci_segments = Some(Box::new([PciSegmentConfig { pci_segment: 0, mmio32_aperture_weight: 0, mmio64_aperture_weight: 1, - }]); + }])); assert_eq!( invalid_config.validate(), Err(ValidationError::InvalidPciSegmentApertureWeight(0)) ); let mut invalid_config = valid_config.clone(); - invalid_config.numa = Some(vec![ + invalid_config.numa = Some(Box::new([ NumaConfig { guest_numa_id: 0, - cpus: Some(vec![0]), + cpus: Some(Box::new([0])), ..numa_fixture() }, NumaConfig { guest_numa_id: 1, - cpus: Some(vec![1]), - pci_segments: Some(vec![0]), + cpus: Some(Box::new([1])), + pci_segments: Some(Box::new([0])), ..numa_fixture() }, - ]); + ])); assert_eq!( invalid_config.validate(), Err(ValidationError::DefaultPciSegmentInvalidNode(1)) ); let mut invalid_config = valid_config.clone(); - invalid_config.numa = Some(vec![ + invalid_config.numa = Some(Box::new([ NumaConfig { guest_numa_id: 0, - cpus: Some(vec![0]), - pci_segments: Some(vec![0]), + cpus: Some(Box::new([0])), + pci_segments: Some(Box::new([0])), ..numa_fixture() }, NumaConfig { guest_numa_id: 1, - cpus: Some(vec![1]), - pci_segments: Some(vec![1]), + cpus: Some(Box::new([1])), + pci_segments: Some(Box::new([1])), ..numa_fixture() }, - ]); + ])); assert_eq!( invalid_config.validate(), Err(ValidationError::InvalidPciSegment(1)) diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index 489b7e5ce..1d1e0d9a9 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -122,7 +122,7 @@ pub struct PlatformConfig { #[serde(default = "default_platformconfig_num_pci_segments")] pub num_pci_segments: u16, #[serde(default)] - pub iommu_segments: Option>, + pub iommu_segments: Option>, #[serde(default = "default_platformconfig_iommu_address_width_bits")] pub iommu_address_width_bits: u8, #[serde(default)] @@ -130,7 +130,7 @@ pub struct PlatformConfig { #[serde(default)] pub uuid: Option, #[serde(default)] - pub oem_strings: Option>, + pub oem_strings: Option>, #[cfg(feature = "tdx")] #[serde(default)] pub tdx: bool, @@ -270,7 +270,7 @@ pub struct RateLimiterGroupConfig { #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct VirtQueueAffinity { pub queue_index: u16, - pub host_cpus: Vec, + pub host_cpus: Box<[usize]>, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] @@ -314,7 +314,7 @@ pub struct DiskConfig { #[serde(default)] pub serial: Option, #[serde(default)] - pub queue_affinity: Option>, + pub queue_affinity: Option>, #[serde(default)] pub backing_files: bool, #[serde(default = "default_diskconfig_sparse")] @@ -782,13 +782,13 @@ pub struct NumaDistance { pub struct NumaConfig { pub guest_numa_id: u32, #[serde(default)] - pub cpus: Option>, + pub cpus: Option>, #[serde(default)] - pub distances: Option>, + pub distances: Option>, #[serde(default)] - pub memory_zones: Option>, + pub memory_zones: Option>, #[serde(default)] - pub pci_segments: Option>, + pub pci_segments: Option>, #[serde(default)] pub device_id: Option, } @@ -1020,7 +1020,7 @@ pub struct VmConfig { #[serde(default)] pub memory: MemoryConfig, pub payload: Option, - pub rate_limit_groups: Option>, + pub rate_limit_groups: Option>, pub disks: Option>, pub net: Option>, #[serde(default)] @@ -1047,13 +1047,13 @@ pub struct VmConfig { pub pvpanic: bool, #[serde(default)] pub iommu: bool, - pub numa: Option>, + pub numa: Option>, #[serde(default)] pub watchdog: bool, #[cfg(feature = "guest_debug")] #[serde(default)] pub gdb: bool, - pub pci_segments: Option>, + pub pci_segments: Option>, pub platform: Option, pub tpm: Option, // Preserved FDs are the ones that share the same life-time as its holding @@ -1068,7 +1068,7 @@ pub struct VmConfig { pub preserved_fds: Option>, #[serde(default)] pub landlock_enable: bool, - pub landlock_rules: Option>, + pub landlock_rules: Option>, #[cfg(feature = "ivshmem")] pub ivshmem: Option, }