mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-19 15:58:25 +00:00
runtime-rs: Add the memory hotplug for cloud-hypervisor
For cloud-hypervisor, currently only hot plugging of memory is supported, but hot unplugging of memory is not supported. In addition, by default, cloud-hypervisor uses ACPI-based memory hot-plugging instead of virtio-mem based memory hot-plugging. Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
This commit is contained in:
@@ -74,8 +74,8 @@ pub struct CloudHypervisorInner {
|
|||||||
// None.
|
// None.
|
||||||
pub(crate) ch_features: Option<Vec<String>>,
|
pub(crate) ch_features: Option<Vec<String>>,
|
||||||
|
|
||||||
/// Size of memory block of guest OS in MB (currently unused)
|
/// Size of memory block of guest OS in MB
|
||||||
pub(crate) _guest_memory_block_size_mb: u32,
|
pub(crate) guest_memory_block_size_mb: u32,
|
||||||
|
|
||||||
pub(crate) exit_notify: Option<mpsc::Sender<i32>>,
|
pub(crate) exit_notify: Option<mpsc::Sender<i32>>,
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ impl CloudHypervisorInner {
|
|||||||
tasks: None,
|
tasks: None,
|
||||||
guest_protection_to_use: GuestProtection::NoProtection,
|
guest_protection_to_use: GuestProtection::NoProtection,
|
||||||
ch_features: None,
|
ch_features: None,
|
||||||
_guest_memory_block_size_mb: 0,
|
guest_memory_block_size_mb: 0,
|
||||||
|
|
||||||
exit_notify,
|
exit_notify,
|
||||||
}
|
}
|
||||||
|
@@ -7,15 +7,18 @@ use super::inner::CloudHypervisorInner;
|
|||||||
use crate::ch::utils::get_api_socket_path;
|
use crate::ch::utils::get_api_socket_path;
|
||||||
use crate::ch::utils::get_vsock_path;
|
use crate::ch::utils::get_vsock_path;
|
||||||
use crate::kernel_param::KernelParams;
|
use crate::kernel_param::KernelParams;
|
||||||
use crate::utils::{get_jailer_root, get_sandbox_path};
|
use crate::utils::{bytes_to_megs, get_jailer_root, get_sandbox_path, megs_to_bytes};
|
||||||
use crate::MemoryConfig;
|
use crate::MemoryConfig;
|
||||||
use crate::VM_ROOTFS_DRIVER_BLK;
|
use crate::VM_ROOTFS_DRIVER_BLK;
|
||||||
use crate::VM_ROOTFS_DRIVER_PMEM;
|
use crate::VM_ROOTFS_DRIVER_PMEM;
|
||||||
use crate::{VcpuThreadIds, VmmState};
|
use crate::{VcpuThreadIds, VmmState};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use ch_config::ch_api::{
|
use ch_config::{
|
||||||
cloud_hypervisor_vm_create, cloud_hypervisor_vm_start, cloud_hypervisor_vmm_ping,
|
ch_api::{
|
||||||
cloud_hypervisor_vmm_shutdown,
|
cloud_hypervisor_vm_create, cloud_hypervisor_vm_info, cloud_hypervisor_vm_resize,
|
||||||
|
cloud_hypervisor_vm_start, cloud_hypervisor_vmm_ping, cloud_hypervisor_vmm_shutdown,
|
||||||
|
},
|
||||||
|
VmResize,
|
||||||
};
|
};
|
||||||
use ch_config::{guest_protection_is_tdx, NamedHypervisorConfig, VmConfig};
|
use ch_config::{guest_protection_is_tdx, NamedHypervisorConfig, VmConfig};
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
@@ -748,17 +751,99 @@ impl CloudHypervisorInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_guest_memory_block_size(&mut self, size: u32) {
|
pub(crate) fn set_guest_memory_block_size(&mut self, size: u32) {
|
||||||
self._guest_memory_block_size_mb = size;
|
self.guest_memory_block_size_mb = bytes_to_megs(size as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn guest_memory_block_size_mb(&self) -> u32 {
|
pub(crate) fn guest_memory_block_size_mb(&self) -> u32 {
|
||||||
self._guest_memory_block_size_mb
|
self.guest_memory_block_size_mb
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resize_memory(&self, _new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
|
pub(crate) async fn resize_memory(&self, new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
|
||||||
warn!(sl!(), "CH memory resize not implemented - see https://github.com/kata-containers/kata-containers/issues/8801");
|
let socket = self
|
||||||
|
.api_socket
|
||||||
|
.as_ref()
|
||||||
|
.ok_or("missing socket")
|
||||||
|
.map_err(|e| anyhow!(e))?;
|
||||||
|
|
||||||
Ok((0, MemoryConfig::default()))
|
let vminfo =
|
||||||
|
cloud_hypervisor_vm_info(socket.try_clone().context("failed to clone socket")?)
|
||||||
|
.await
|
||||||
|
.context("get vminfo")?;
|
||||||
|
|
||||||
|
let current_mem_size = vminfo.config.memory.size;
|
||||||
|
let new_total_mem = megs_to_bytes(new_mem_mb);
|
||||||
|
|
||||||
|
info!(
|
||||||
|
sl!(),
|
||||||
|
"cloud-hypervisor::resize_memory(): asked to resize memory to {} MB, current memory is {} MB", new_mem_mb, bytes_to_megs(current_mem_size)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Early Check to verify if boot memory is the same as requested
|
||||||
|
if current_mem_size == new_total_mem {
|
||||||
|
info!(sl!(), "VM alreay has requested memory");
|
||||||
|
return Ok((new_mem_mb, MemoryConfig::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if current_mem_size > new_total_mem {
|
||||||
|
info!(sl!(), "Remove memory is not supported, nothing to do");
|
||||||
|
return Ok((new_mem_mb, MemoryConfig::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let guest_mem_block_size = megs_to_bytes(self.guest_memory_block_size_mb);
|
||||||
|
|
||||||
|
let mut new_hotplugged_mem = new_total_mem - current_mem_size;
|
||||||
|
|
||||||
|
info!(
|
||||||
|
sl!(),
|
||||||
|
"new hotplugged mem before alignment: {} B ({} MB), guest_mem_block_size: {} MB",
|
||||||
|
new_hotplugged_mem,
|
||||||
|
bytes_to_megs(new_hotplugged_mem),
|
||||||
|
bytes_to_megs(guest_mem_block_size)
|
||||||
|
);
|
||||||
|
|
||||||
|
let is_unaligned = new_hotplugged_mem % guest_mem_block_size != 0;
|
||||||
|
if is_unaligned {
|
||||||
|
new_hotplugged_mem = ch_config::convert::checked_next_multiple_of(
|
||||||
|
new_hotplugged_mem,
|
||||||
|
guest_mem_block_size,
|
||||||
|
)
|
||||||
|
.ok_or(anyhow!(format!(
|
||||||
|
"alignment of {} B to the block size of {} B failed",
|
||||||
|
new_hotplugged_mem, guest_mem_block_size
|
||||||
|
)))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_total_mem_aligned = new_hotplugged_mem + current_mem_size;
|
||||||
|
|
||||||
|
let max_total_mem = megs_to_bytes(self.config.memory_info.default_maxmemory);
|
||||||
|
if new_total_mem_aligned > max_total_mem {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"requested memory ({} MB) is greater than maximum allowed ({} MB)",
|
||||||
|
bytes_to_megs(new_total_mem_aligned),
|
||||||
|
self.config.memory_info.default_maxmemory
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
sl!(),
|
||||||
|
"hotplugged mem from {} MB to {} MB)",
|
||||||
|
bytes_to_megs(current_mem_size),
|
||||||
|
bytes_to_megs(new_total_mem_aligned)
|
||||||
|
);
|
||||||
|
|
||||||
|
let vmresize = VmResize {
|
||||||
|
desired_ram: Some(new_total_mem_aligned),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
cloud_hypervisor_vm_resize(
|
||||||
|
socket.try_clone().context("failed to clone socket")?,
|
||||||
|
vmresize,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("resize memory")?;
|
||||||
|
|
||||||
|
Ok((new_mem_mb, MemoryConfig::default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -206,7 +206,7 @@ impl Hypervisor for CloudHypervisor {
|
|||||||
|
|
||||||
async fn resize_memory(&self, new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
|
async fn resize_memory(&self, new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
|
||||||
let inner = self.inner.read().await;
|
let inner = self.inner.read().await;
|
||||||
inner.resize_memory(new_mem_mb)
|
inner.resize_memory(new_mem_mb).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_passfd_listener_addr(&self) -> Result<(String, u32)> {
|
async fn get_passfd_listener_addr(&self) -> Result<(String, u32)> {
|
||||||
|
Reference in New Issue
Block a user