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 <Henry.Wang@arm.com>
This commit is contained in:
Henry Wang 2021-08-07 06:15:13 -04:00 committed by Sebastien Boeuf
parent f3197c3833
commit bcae6c41e3
2 changed files with 41 additions and 6 deletions

View File

@ -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 referring to an existing memory zone identifier. Values are separated from
each other with the `:` separator. 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_ _Example_
``` ```

View File

@ -8,6 +8,7 @@ use net_util::MacAddr;
use option_parser::{ use option_parser::{
ByteSized, IntegerList, OptionParser, OptionParserError, StringList, Toggle, TupleTwoIntegers, ByteSized, IntegerList, OptionParser, OptionParserError, StringList, Toggle, TupleTwoIntegers,
}; };
use std::collections::HashMap;
use std::convert::From; use std::convert::From;
use std::fmt; use std::fmt;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
@ -126,20 +127,22 @@ pub enum ValidationError {
VnetQueueFdMismatch, VnetQueueFdMismatch,
/// Using reserved fd /// Using reserved fd
VnetReservedFd, VnetReservedFd,
// Hugepages not turned on /// Hugepages not turned on
HugePageSizeWithoutHugePages, HugePageSizeWithoutHugePages,
// Huge page size is not power of 2 /// Huge page size is not power of 2
InvalidHugePageSize(u64), InvalidHugePageSize(u64),
// CPU Hotplug not permitted with TDX /// CPU Hotplug not permitted with TDX
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
TdxNoCpuHotplug, TdxNoCpuHotplug,
// Specifying kernel not permitted with TDX /// Specifying kernel not permitted with TDX
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
TdxKernelSpecified, TdxKernelSpecified,
// Insuffient vCPUs for queues /// Insuffient vCPUs for queues
TooManyQueues, TooManyQueues,
// Need shared memory for vfio-user /// Need shared memory for vfio-user
UserDevicesRequireSharedMemory, UserDevicesRequireSharedMemory,
/// Memory zone is reused across NUMA nodes
MemoryZoneReused(String, u32, u32),
} }
type ValidationResult<T> = std::result::Result<T, ValidationError>; type ValidationResult<T> = std::result::Result<T, ValidationError>;
@ -190,6 +193,13 @@ impl fmt::Display for ValidationError {
UserDevicesRequireSharedMemory => { UserDevicesRequireSharedMemory => {
write!(f, "Using user devices requires using shared memory") 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); 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(()) Ok(())
} }