diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 776da603b..992436d60 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -18,6 +18,8 @@ use crate::device_tree::{DeviceNode, DeviceTree}; use crate::interrupt::kvm::KvmMsiInterruptManager as MsiInterruptManager; use crate::interrupt::LegacyUserspaceInterruptManager; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; +#[cfg(feature = "acpi")] +use crate::vm::NumaNodes; #[cfg(feature = "pci_support")] use crate::PciDeviceInfo; use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID}; @@ -805,9 +807,14 @@ pub struct DeviceManager { // seccomp action seccomp_action: SeccompAction, + + // List of guest NUMA nodes. + #[cfg(feature = "acpi")] + numa_nodes: NumaNodes, } impl DeviceManager { + #[allow(clippy::too_many_arguments)] pub fn new( vm: Arc, config: Arc>, @@ -816,6 +823,7 @@ impl DeviceManager { #[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd, vmm_path: PathBuf, seccomp_action: SeccompAction, + #[cfg(feature = "acpi")] numa_nodes: NumaNodes, ) -> DeviceManagerResult>> { let device_tree = Arc::new(Mutex::new(DeviceTree::new())); @@ -878,6 +886,8 @@ impl DeviceManager { #[cfg(target_arch = "aarch64")] id_to_dev_info: HashMap::new(), seccomp_action, + #[cfg(feature = "acpi")] + numa_nodes, }; #[cfg(feature = "acpi")] @@ -2419,13 +2429,19 @@ impl DeviceManager { let mm = self.memory_manager.clone(); let mm = mm.lock().unwrap(); - for (_, memory_zone) in mm.memory_zones().iter() { + for (_memory_zone_id, memory_zone) in mm.memory_zones().iter() { if let (Some(region), Some(resize)) = ( memory_zone.virtio_mem_region(), memory_zone.virtio_mem_resize(), ) { let id = self.next_device_name(MEM_DEVICE_NAME_PREFIX)?; + #[cfg(not(feature = "acpi"))] + let node_id: Option = None; + #[cfg(feature = "acpi")] + let node_id = numa_node_id_from_memory_zone_id(&self.numa_nodes, _memory_zone_id) + .map(|i| i as u16); + let virtio_mem_device = Arc::new(Mutex::new( virtio_devices::Mem::new( id.clone(), @@ -2434,7 +2450,7 @@ impl DeviceManager { .try_clone() .map_err(DeviceManagerError::TryCloneVirtioMemResize)?, self.seccomp_action.clone(), - None, + node_id, ) .map_err(DeviceManagerError::CreateVirtioMem)?, )); @@ -3356,6 +3372,20 @@ impl DeviceManager { } } +#[cfg(feature = "acpi")] +fn numa_node_id_from_memory_zone_id(numa_nodes: &NumaNodes, memory_zone_id: &str) -> Option { + for (numa_node_id, numa_node) in numa_nodes.iter() { + if numa_node + .memory_zones() + .contains(&memory_zone_id.to_owned()) + { + return Some(*numa_node_id); + } + } + + None +} + #[cfg(feature = "acpi")] struct PciDevSlot { device_id: u8, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 6a02097af..122dbcacd 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -212,11 +212,12 @@ pub enum Error { } pub type Result = result::Result; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct NumaNode { memory_regions: Vec>, cpus: Vec, distances: BTreeMap, + memory_zones: Vec, } impl NumaNode { @@ -231,6 +232,10 @@ impl NumaNode { pub fn distances(&self) -> &BTreeMap { &self.distances } + + pub fn memory_zones(&self) -> &Vec { + &self.memory_zones + } } pub type NumaNodes = BTreeMap; @@ -317,6 +322,11 @@ impl Vm { .validate() .map_err(Error::ConfigValidation)?; + // Create NUMA nodes based on NumaConfig. + #[cfg(feature = "acpi")] + let numa_nodes = + Self::create_numa_nodes(config.lock().unwrap().numa.clone(), &memory_manager)?; + let device_manager = DeviceManager::new( vm.clone(), config.clone(), @@ -325,6 +335,8 @@ impl Vm { &reset_evt, vmm_path, seccomp_action.clone(), + #[cfg(feature = "acpi")] + numa_nodes.clone(), ) .map_err(Error::DeviceManager)?; @@ -352,11 +364,6 @@ impl Vm { .transpose() .map_err(Error::InitramfsFile)?; - // Create NUMA nodes based on NumaConfig. - #[cfg(feature = "acpi")] - let numa_nodes = - Self::create_numa_nodes(config.lock().unwrap().numa.clone(), &memory_manager)?; - Ok(Vm { kernel, initramfs, @@ -395,16 +402,13 @@ impl Vm { return Err(Error::InvalidNumaConfig); } - let mut node = NumaNode { - memory_regions: Vec::new(), - cpus: Vec::new(), - distances: BTreeMap::new(), - }; + let mut node = NumaNode::default(); if let Some(memory_zones) = &config.memory_zones { for memory_zone in memory_zones.iter() { if let Some(mm_zone) = mm_zones.get(memory_zone) { node.memory_regions.extend(mm_zone.regions().clone()); + node.memory_zones.push(memory_zone.clone()); } else { error!("Unknown memory zone '{}'", memory_zone); return Err(Error::InvalidNumaConfig);