mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-05 12:25:19 +00:00
vmm: Add support for virtio-mem
This commit adds new option hotplug_method to memory config. It can set the hotplug method to "acpi" or "virtio-mem". Signed-off-by: Hui Zhu <teawater@antfin.com>
This commit is contained in:
parent
51d102c708
commit
e6b934a56a
@ -100,6 +100,7 @@ fn create_app<'a, 'b>(
|
|||||||
.help(
|
.help(
|
||||||
"Memory parameters \
|
"Memory parameters \
|
||||||
\"size=<guest_memory_size>,file=<backing_file_path>,mergeable=on|off,\
|
\"size=<guest_memory_size>,file=<backing_file_path>,mergeable=on|off,\
|
||||||
|
hotplug_method=acpi|virtio-mem,\
|
||||||
hotplug_size=<hotpluggable_memory_size>\"",
|
hotplug_size=<hotpluggable_memory_size>\"",
|
||||||
)
|
)
|
||||||
.default_value(&default_memory)
|
.default_value(&default_memory)
|
||||||
@ -412,6 +413,7 @@ extern crate credibility;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod unit_tests {
|
mod unit_tests {
|
||||||
|
use crate::config::HotplugMethod;
|
||||||
use crate::{create_app, prepare_default_values};
|
use crate::{create_app, prepare_default_values};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use vmm::config::{
|
use vmm::config::{
|
||||||
@ -476,6 +478,7 @@ mod unit_tests {
|
|||||||
size: 536_870_912,
|
size: 536_870_912,
|
||||||
file: None,
|
file: None,
|
||||||
mergeable: false,
|
mergeable: false,
|
||||||
|
hotplug_method: HotplugMethod::Acpi,
|
||||||
hotplug_size: None,
|
hotplug_size: None,
|
||||||
},
|
},
|
||||||
kernel: None,
|
kernel: None,
|
||||||
|
@ -31,6 +31,8 @@ pub enum Error {
|
|||||||
ParseCpusUnknownParam,
|
ParseCpusUnknownParam,
|
||||||
/// Max is less than boot
|
/// Max is less than boot
|
||||||
ParseCpusMaxLowerThanBoot,
|
ParseCpusMaxLowerThanBoot,
|
||||||
|
/// Failed parsing memory hotplug_method parameter.
|
||||||
|
ParseMemoryHotplugMethodParam,
|
||||||
/// Failed parsing memory file parameter.
|
/// Failed parsing memory file parameter.
|
||||||
ParseMemoryFileParam,
|
ParseMemoryFileParam,
|
||||||
/// Failed parsing kernel parameters.
|
/// Failed parsing kernel parameters.
|
||||||
@ -246,6 +248,18 @@ impl Default for CpusConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub enum HotplugMethod {
|
||||||
|
Acpi,
|
||||||
|
VirtioMem,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HotplugMethod {
|
||||||
|
fn default() -> Self {
|
||||||
|
HotplugMethod::Acpi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct MemoryConfig {
|
pub struct MemoryConfig {
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
@ -254,6 +268,8 @@ pub struct MemoryConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub mergeable: bool,
|
pub mergeable: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub hotplug_method: HotplugMethod,
|
||||||
|
#[serde(default)]
|
||||||
pub hotplug_size: Option<u64>,
|
pub hotplug_size: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,6 +282,7 @@ impl MemoryConfig {
|
|||||||
let mut file_str: &str = "";
|
let mut file_str: &str = "";
|
||||||
let mut mergeable_str: &str = "";
|
let mut mergeable_str: &str = "";
|
||||||
let mut backed = false;
|
let mut backed = false;
|
||||||
|
let mut hotplug_method_str: &str = "acpi";
|
||||||
let mut hotplug_str: &str = "";
|
let mut hotplug_str: &str = "";
|
||||||
|
|
||||||
for param in params_list.iter() {
|
for param in params_list.iter() {
|
||||||
@ -276,6 +293,8 @@ impl MemoryConfig {
|
|||||||
file_str = ¶m[5..];
|
file_str = ¶m[5..];
|
||||||
} else if param.starts_with("mergeable=") {
|
} else if param.starts_with("mergeable=") {
|
||||||
mergeable_str = ¶m[10..];
|
mergeable_str = ¶m[10..];
|
||||||
|
} else if param.starts_with("hotplug_method=") {
|
||||||
|
hotplug_method_str = ¶m[15..];
|
||||||
} else if param.starts_with("hotplug_size=") {
|
} else if param.starts_with("hotplug_size=") {
|
||||||
hotplug_str = ¶m[13..]
|
hotplug_str = ¶m[13..]
|
||||||
}
|
}
|
||||||
@ -291,10 +310,18 @@ impl MemoryConfig {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let hotplug_method_str = hotplug_method_str.to_string().to_lowercase();
|
||||||
|
let hotplug_method = match &hotplug_method_str[..] {
|
||||||
|
"acpi" => HotplugMethod::Acpi,
|
||||||
|
"virtio-mem" => HotplugMethod::VirtioMem,
|
||||||
|
_ => return Err(Error::ParseMemoryHotplugMethodParam),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(MemoryConfig {
|
Ok(MemoryConfig {
|
||||||
size: parse_size(size_str)?,
|
size: parse_size(size_str)?,
|
||||||
file,
|
file,
|
||||||
mergeable: parse_on_off(mergeable_str)?,
|
mergeable: parse_on_off(mergeable_str)?,
|
||||||
|
hotplug_method,
|
||||||
hotplug_size: if hotplug_str == "" {
|
hotplug_size: if hotplug_str == "" {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -310,6 +337,7 @@ impl Default for MemoryConfig {
|
|||||||
size: DEFAULT_MEMORY_MB << 20,
|
size: DEFAULT_MEMORY_MB << 20,
|
||||||
file: None,
|
file: None,
|
||||||
mergeable: false,
|
mergeable: false,
|
||||||
|
hotplug_method: HotplugMethod::Acpi,
|
||||||
hotplug_size: None,
|
hotplug_size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use crate::config::HotplugMethod;
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
use acpi_tables::{aml, aml::Aml};
|
use acpi_tables::{aml, aml::Aml};
|
||||||
use arch::RegionType;
|
use arch::RegionType;
|
||||||
@ -45,8 +46,12 @@ pub struct MemoryManager {
|
|||||||
backing_file: Option<PathBuf>,
|
backing_file: Option<PathBuf>,
|
||||||
mergeable: bool,
|
mergeable: bool,
|
||||||
allocator: Arc<Mutex<SystemAllocator>>,
|
allocator: Arc<Mutex<SystemAllocator>>,
|
||||||
|
hotplug_method: HotplugMethod,
|
||||||
|
boot_ram: u64,
|
||||||
current_ram: u64,
|
current_ram: u64,
|
||||||
next_hotplug_slot: usize,
|
next_hotplug_slot: usize,
|
||||||
|
pub virtiomem_region: Option<Arc<GuestRegionMmap>>,
|
||||||
|
pub virtiomem_resize: Option<vm_virtio::Resize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -80,6 +85,15 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Failed to set the user memory region.
|
/// Failed to set the user memory region.
|
||||||
SetUserMemoryRegion(kvm_ioctls::Error),
|
SetUserMemoryRegion(kvm_ioctls::Error),
|
||||||
|
|
||||||
|
/// Failed to EventFd.
|
||||||
|
EventFdFail(std::io::Error),
|
||||||
|
|
||||||
|
/// Eventfd write error
|
||||||
|
EventfdError(std::io::Error),
|
||||||
|
|
||||||
|
/// Failed to virtio-mem resize
|
||||||
|
VirtioMemResizeFail(vm_virtio::mem::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||||
@ -195,6 +209,7 @@ impl MemoryManager {
|
|||||||
allocator: Arc<Mutex<SystemAllocator>>,
|
allocator: Arc<Mutex<SystemAllocator>>,
|
||||||
fd: Arc<VmFd>,
|
fd: Arc<VmFd>,
|
||||||
boot_ram: u64,
|
boot_ram: u64,
|
||||||
|
hotplug_method: HotplugMethod,
|
||||||
hotplug_size: Option<u64>,
|
hotplug_size: Option<u64>,
|
||||||
backing_file: &Option<PathBuf>,
|
backing_file: &Option<PathBuf>,
|
||||||
mergeable: bool,
|
mergeable: bool,
|
||||||
@ -228,9 +243,27 @@ impl MemoryManager {
|
|||||||
mem_end.unchecked_add(1)
|
mem_end.unchecked_add(1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut virtiomem_region = None;
|
||||||
|
let mut virtiomem_resize = None;
|
||||||
if let Some(size) = hotplug_size {
|
if let Some(size) = hotplug_size {
|
||||||
|
if hotplug_method == HotplugMethod::VirtioMem {
|
||||||
|
let start_addr = GuestAddress(
|
||||||
|
(start_of_device_area.0 + vm_virtio::VIRTIO_MEM_DEFAULT_BLOCK_SIZE - 1)
|
||||||
|
& (!(vm_virtio::VIRTIO_MEM_DEFAULT_BLOCK_SIZE - 1)),
|
||||||
|
);
|
||||||
|
virtiomem_region = Some(MemoryManager::create_ram_region(
|
||||||
|
backing_file,
|
||||||
|
start_addr,
|
||||||
|
size as usize,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
virtiomem_resize = Some(vm_virtio::Resize::new().map_err(Error::EventFdFail)?);
|
||||||
|
|
||||||
|
start_of_device_area = start_addr.unchecked_add(size);
|
||||||
|
} else {
|
||||||
start_of_device_area = start_of_device_area.unchecked_add(size);
|
start_of_device_area = start_of_device_area.unchecked_add(size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let guest_memory = GuestMemoryAtomic::new(guest_memory);
|
let guest_memory = GuestMemoryAtomic::new(guest_memory);
|
||||||
|
|
||||||
@ -248,8 +281,12 @@ impl MemoryManager {
|
|||||||
backing_file: backing_file.clone(),
|
backing_file: backing_file.clone(),
|
||||||
mergeable,
|
mergeable,
|
||||||
allocator: allocator.clone(),
|
allocator: allocator.clone(),
|
||||||
|
hotplug_method,
|
||||||
|
boot_ram,
|
||||||
current_ram: boot_ram,
|
current_ram: boot_ram,
|
||||||
next_hotplug_slot: 0,
|
next_hotplug_slot: 0,
|
||||||
|
virtiomem_region: virtiomem_region.clone(),
|
||||||
|
virtiomem_resize,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
guest_memory.memory().with_regions(|_, region| {
|
guest_memory.memory().with_regions(|_, region| {
|
||||||
@ -263,6 +300,21 @@ impl MemoryManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if let Some(region) = virtiomem_region {
|
||||||
|
memory_manager.lock().unwrap().create_userspace_mapping(
|
||||||
|
region.start_addr().raw_value(),
|
||||||
|
region.len() as u64,
|
||||||
|
region.as_ptr() as u64,
|
||||||
|
mergeable,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
allocator
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.allocate_mmio_addresses(Some(region.start_addr()), region.len(), None)
|
||||||
|
.ok_or(Error::MemoryRangeAllocation)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate RAM and Reserved address ranges.
|
// Allocate RAM and Reserved address ranges.
|
||||||
for region in arch_mem_regions.iter() {
|
for region in arch_mem_regions.iter() {
|
||||||
allocator
|
allocator
|
||||||
@ -315,6 +367,18 @@ impl MemoryManager {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the GuestMemoryMmap with the new range
|
||||||
|
fn add_region(&mut self, region: Arc<GuestRegionMmap>) -> Result<(), Error> {
|
||||||
|
let guest_memory = self
|
||||||
|
.guest_memory
|
||||||
|
.memory()
|
||||||
|
.insert_region(region)
|
||||||
|
.map_err(Error::GuestMemory)?;
|
||||||
|
self.guest_memory.lock().unwrap().replace(guest_memory);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn hotplug_ram_region(&mut self, size: usize) -> Result<(), Error> {
|
fn hotplug_ram_region(&mut self, size: usize) -> Result<(), Error> {
|
||||||
info!("Hotplugging new RAM: {}", size);
|
info!("Hotplugging new RAM: {}", size);
|
||||||
|
|
||||||
@ -370,13 +434,7 @@ impl MemoryManager {
|
|||||||
|
|
||||||
self.next_hotplug_slot += 1;
|
self.next_hotplug_slot += 1;
|
||||||
|
|
||||||
// Update the GuestMemoryMmap with the new range
|
self.add_region(region)?;
|
||||||
let guest_memory = self
|
|
||||||
.guest_memory
|
|
||||||
.memory()
|
|
||||||
.insert_region(region)
|
|
||||||
.map_err(Error::GuestMemory)?;
|
|
||||||
self.guest_memory.lock().unwrap().replace(guest_memory);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -453,16 +511,41 @@ impl MemoryManager {
|
|||||||
Ok(slot)
|
Ok(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn virtiomem_resize(&mut self, size: u64) -> Result<(), Error> {
|
||||||
|
let region = self.virtiomem_region.take();
|
||||||
|
if let Some(region) = region {
|
||||||
|
self.add_region(region)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(resize) = &self.virtiomem_resize {
|
||||||
|
resize.work(size).map_err(Error::VirtioMemResizeFail)?;
|
||||||
|
} else {
|
||||||
|
panic!("should not fail here");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, desired_ram: u64) -> Result<bool, Error> {
|
pub fn resize(&mut self, desired_ram: u64) -> Result<bool, Error> {
|
||||||
if desired_ram > self.current_ram {
|
let mut notify_hotplug = false;
|
||||||
|
match self.hotplug_method {
|
||||||
|
HotplugMethod::VirtioMem => {
|
||||||
|
if desired_ram >= self.boot_ram {
|
||||||
|
self.virtiomem_resize(desired_ram - self.boot_ram)?;
|
||||||
|
self.current_ram = desired_ram;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HotplugMethod::Acpi => {
|
||||||
|
if desired_ram >= self.current_ram {
|
||||||
self.hotplug_ram_region((desired_ram - self.current_ram) as usize)?;
|
self.hotplug_ram_region((desired_ram - self.current_ram) as usize)?;
|
||||||
self.current_ram = desired_ram;
|
self.current_ram = desired_ram;
|
||||||
Ok(true)
|
notify_hotplug = true
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(notify_hotplug)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
struct MemoryNotify {
|
struct MemoryNotify {
|
||||||
|
@ -169,6 +169,9 @@ pub enum Error {
|
|||||||
|
|
||||||
/// No PCI support
|
/// No PCI support
|
||||||
NoPciSupport,
|
NoPciSupport,
|
||||||
|
|
||||||
|
/// Eventfd write error
|
||||||
|
EventfdError(std::io::Error),
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
@ -337,6 +340,7 @@ impl Vm {
|
|||||||
allocator.clone(),
|
allocator.clone(),
|
||||||
fd.clone(),
|
fd.clone(),
|
||||||
memory_config.size,
|
memory_config.size,
|
||||||
|
memory_config.hotplug_method,
|
||||||
memory_config.hotplug_size,
|
memory_config.hotplug_size,
|
||||||
&memory_config.file,
|
&memory_config.file,
|
||||||
memory_config.mergeable,
|
memory_config.mergeable,
|
||||||
|
Loading…
Reference in New Issue
Block a user