From bcae6c41e32d54c6782dd801ea1dd5547adbd7c6 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Sat, 7 Aug 2021 06:15:13 -0400 Subject: [PATCH] vmm, doc: Forbid same memory zone in multiple NUMA nodes It is forbidden that the same memory zone belongs to more than one NUMA node. This commit adds related validation to the `--numa` parameter to prevent the user from specifying such configuration. Signed-off-by: Henry Wang --- docs/memory.md | 4 ++++ vmm/src/config.rs | 43 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/memory.md b/docs/memory.md index c3bed5f9c..1b69961f0 100644 --- a/docs/memory.md +++ b/docs/memory.md @@ -441,6 +441,10 @@ Multiple values can be provided to define the list. Each value is a string referring to an existing memory zone identifier. Values are separated from each other with the `:` separator. +Note that a memory zone must belong to a single NUMA node. The following +configuration is incorrect, therefore not allowed: +`--numa guest_numa_id=0,memory_zones=mem0 guest_numa_id=1,memory_zones=mem0` + _Example_ ``` diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 5081c3755..93e10b4ed 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -8,6 +8,7 @@ use net_util::MacAddr; use option_parser::{ ByteSized, IntegerList, OptionParser, OptionParserError, StringList, Toggle, TupleTwoIntegers, }; +use std::collections::HashMap; use std::convert::From; use std::fmt; use std::net::Ipv4Addr; @@ -126,20 +127,22 @@ pub enum ValidationError { VnetQueueFdMismatch, /// Using reserved fd VnetReservedFd, - // Hugepages not turned on + /// Hugepages not turned on HugePageSizeWithoutHugePages, - // Huge page size is not power of 2 + /// Huge page size is not power of 2 InvalidHugePageSize(u64), - // CPU Hotplug not permitted with TDX + /// CPU Hotplug not permitted with TDX #[cfg(feature = "tdx")] TdxNoCpuHotplug, - // Specifying kernel not permitted with TDX + /// Specifying kernel not permitted with TDX #[cfg(feature = "tdx")] TdxKernelSpecified, - // Insuffient vCPUs for queues + /// Insuffient vCPUs for queues TooManyQueues, - // Need shared memory for vfio-user + /// Need shared memory for vfio-user UserDevicesRequireSharedMemory, + /// Memory zone is reused across NUMA nodes + MemoryZoneReused(String, u32, u32), } type ValidationResult = std::result::Result; @@ -190,6 +193,13 @@ impl fmt::Display for ValidationError { UserDevicesRequireSharedMemory => { write!(f, "Using user devices requires using shared memory") } + MemoryZoneReused(s, u1, u2) => { + write!( + f, + "Memory zone: {} belongs to multiple NUMA nodes {} and {}", + s, u1, u2 + ) + } } } } @@ -1915,6 +1925,27 @@ impl VmConfig { return Err(ValidationError::UserDevicesRequireSharedMemory); } } + + if let Some(numa) = &self.numa { + let mut used_numa_node_memory_zones = HashMap::new(); + for numa_node in numa.iter() { + for memory_zone in numa_node.memory_zones.clone().unwrap().iter() { + if !used_numa_node_memory_zones.contains_key(memory_zone) { + used_numa_node_memory_zones + .insert(memory_zone.to_string(), numa_node.guest_numa_id); + } else { + return Err(ValidationError::MemoryZoneReused( + memory_zone.to_string(), + *used_numa_node_memory_zones + .get(&memory_zone.to_string()) + .unwrap(), + numa_node.guest_numa_id, + )); + } + } + } + } + Ok(()) }