vmm: Create virtio-mem device with appropriate NUMA node

Now that virtio-mem device accept a guest NUMA node as parameter, we
retrieve this information from the list of NUMA nodes. Based on the
memory zone associated with the virtio-mem device, we obtain the NUMA
node identifier, which we provide to the virtio-mem device.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2020-09-11 16:15:29 +02:00
parent dcedd4cded
commit eb7b923e22
2 changed files with 47 additions and 13 deletions

View File

@@ -18,6 +18,8 @@ use crate::device_tree::{DeviceNode, DeviceTree};
use crate::interrupt::kvm::KvmMsiInterruptManager as MsiInterruptManager; use crate::interrupt::kvm::KvmMsiInterruptManager as MsiInterruptManager;
use crate::interrupt::LegacyUserspaceInterruptManager; use crate::interrupt::LegacyUserspaceInterruptManager;
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
#[cfg(feature = "acpi")]
use crate::vm::NumaNodes;
#[cfg(feature = "pci_support")] #[cfg(feature = "pci_support")]
use crate::PciDeviceInfo; use crate::PciDeviceInfo;
use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID}; use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID};
@@ -805,9 +807,14 @@ pub struct DeviceManager {
// seccomp action // seccomp action
seccomp_action: SeccompAction, seccomp_action: SeccompAction,
// List of guest NUMA nodes.
#[cfg(feature = "acpi")]
numa_nodes: NumaNodes,
} }
impl DeviceManager { impl DeviceManager {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
vm: Arc<dyn hypervisor::Vm>, vm: Arc<dyn hypervisor::Vm>,
config: Arc<Mutex<VmConfig>>, config: Arc<Mutex<VmConfig>>,
@@ -816,6 +823,7 @@ impl DeviceManager {
#[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd, #[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd,
vmm_path: PathBuf, vmm_path: PathBuf,
seccomp_action: SeccompAction, seccomp_action: SeccompAction,
#[cfg(feature = "acpi")] numa_nodes: NumaNodes,
) -> DeviceManagerResult<Arc<Mutex<Self>>> { ) -> DeviceManagerResult<Arc<Mutex<Self>>> {
let device_tree = Arc::new(Mutex::new(DeviceTree::new())); let device_tree = Arc::new(Mutex::new(DeviceTree::new()));
@@ -878,6 +886,8 @@ impl DeviceManager {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
id_to_dev_info: HashMap::new(), id_to_dev_info: HashMap::new(),
seccomp_action, seccomp_action,
#[cfg(feature = "acpi")]
numa_nodes,
}; };
#[cfg(feature = "acpi")] #[cfg(feature = "acpi")]
@@ -2419,13 +2429,19 @@ impl DeviceManager {
let mm = self.memory_manager.clone(); let mm = self.memory_manager.clone();
let mm = mm.lock().unwrap(); 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)) = ( if let (Some(region), Some(resize)) = (
memory_zone.virtio_mem_region(), memory_zone.virtio_mem_region(),
memory_zone.virtio_mem_resize(), memory_zone.virtio_mem_resize(),
) { ) {
let id = self.next_device_name(MEM_DEVICE_NAME_PREFIX)?; let id = self.next_device_name(MEM_DEVICE_NAME_PREFIX)?;
#[cfg(not(feature = "acpi"))]
let node_id: Option<u16> = 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( let virtio_mem_device = Arc::new(Mutex::new(
virtio_devices::Mem::new( virtio_devices::Mem::new(
id.clone(), id.clone(),
@@ -2434,7 +2450,7 @@ impl DeviceManager {
.try_clone() .try_clone()
.map_err(DeviceManagerError::TryCloneVirtioMemResize)?, .map_err(DeviceManagerError::TryCloneVirtioMemResize)?,
self.seccomp_action.clone(), self.seccomp_action.clone(),
None, node_id,
) )
.map_err(DeviceManagerError::CreateVirtioMem)?, .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<u32> {
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")] #[cfg(feature = "acpi")]
struct PciDevSlot { struct PciDevSlot {
device_id: u8, device_id: u8,

View File

@@ -212,11 +212,12 @@ pub enum Error {
} }
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
#[derive(Clone)] #[derive(Clone, Default)]
pub struct NumaNode { pub struct NumaNode {
memory_regions: Vec<Arc<GuestRegionMmap>>, memory_regions: Vec<Arc<GuestRegionMmap>>,
cpus: Vec<u8>, cpus: Vec<u8>,
distances: BTreeMap<u32, u8>, distances: BTreeMap<u32, u8>,
memory_zones: Vec<String>,
} }
impl NumaNode { impl NumaNode {
@@ -231,6 +232,10 @@ impl NumaNode {
pub fn distances(&self) -> &BTreeMap<u32, u8> { pub fn distances(&self) -> &BTreeMap<u32, u8> {
&self.distances &self.distances
} }
pub fn memory_zones(&self) -> &Vec<String> {
&self.memory_zones
}
} }
pub type NumaNodes = BTreeMap<u32, NumaNode>; pub type NumaNodes = BTreeMap<u32, NumaNode>;
@@ -317,6 +322,11 @@ impl Vm {
.validate() .validate()
.map_err(Error::ConfigValidation)?; .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( let device_manager = DeviceManager::new(
vm.clone(), vm.clone(),
config.clone(), config.clone(),
@@ -325,6 +335,8 @@ impl Vm {
&reset_evt, &reset_evt,
vmm_path, vmm_path,
seccomp_action.clone(), seccomp_action.clone(),
#[cfg(feature = "acpi")]
numa_nodes.clone(),
) )
.map_err(Error::DeviceManager)?; .map_err(Error::DeviceManager)?;
@@ -352,11 +364,6 @@ impl Vm {
.transpose() .transpose()
.map_err(Error::InitramfsFile)?; .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 { Ok(Vm {
kernel, kernel,
initramfs, initramfs,
@@ -395,16 +402,13 @@ impl Vm {
return Err(Error::InvalidNumaConfig); return Err(Error::InvalidNumaConfig);
} }
let mut node = NumaNode { let mut node = NumaNode::default();
memory_regions: Vec::new(),
cpus: Vec::new(),
distances: BTreeMap::new(),
};
if let Some(memory_zones) = &config.memory_zones { if let Some(memory_zones) = &config.memory_zones {
for memory_zone in memory_zones.iter() { for memory_zone in memory_zones.iter() {
if let Some(mm_zone) = mm_zones.get(memory_zone) { if let Some(mm_zone) = mm_zones.get(memory_zone) {
node.memory_regions.extend(mm_zone.regions().clone()); node.memory_regions.extend(mm_zone.regions().clone());
node.memory_zones.push(memory_zone.clone());
} else { } else {
error!("Unknown memory zone '{}'", memory_zone); error!("Unknown memory zone '{}'", memory_zone);
return Err(Error::InvalidNumaConfig); return Err(Error::InvalidNumaConfig);