mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-07-07 19:06:16 +00:00
runtime-rs: Add virtio-mem configuration and QMP operations
Add infrastructure for virtio-mem memory hotplug on s390x:
1. QMP Operations (qmp.rs):
- setup_virtio_mem(): Creates virtio-mem-ccw device with CCW
addressing (fe.0.dddd format). Takes primitive parameters
(default_memory, default_maxmemory, machine_type, shared_fs)
and determines memory backend inline based on shared filesystem
configuration.
- resize_virtio_mem(): Adjusts memory via QMP qom-set command
with inline size validation.
- cleanup_virtio_mem_setup(): Error handling helper for setup
failures.
2. Build System:
- Updated configuration template with enable_virtio_mem parameter
- Added DEFENABLEVIRTIOMEM to Makefile
- Updated s390x-options.mk
Assisted-by: IBM Bob
Signed-off-by: Annu Sharma <annu-sharma@ibm.com>
This commit is contained in:
@@ -205,6 +205,7 @@ DEFEMPTYDIRMODE_COCO := block-encrypted
|
||||
##VAR DEFAULTEXPFEATURES=[features] Default experimental features enabled
|
||||
DEFAULTEXPFEATURES := []
|
||||
DEFDISABLESELINUX := false
|
||||
DEFENABLEVIRTIOMEM ?= false
|
||||
##VAR DEFENTROPYSOURCE=[entropy_source] Default entropy source
|
||||
DEFENTROPYSOURCE := /dev/urandom
|
||||
DEFVALIDENTROPYSOURCES := [\"/dev/urandom\",\"/dev/random\",\"\"]
|
||||
@@ -754,6 +755,7 @@ USER_VARS += DEFSANDBOXCGROUPONLY_QEMU
|
||||
USER_VARS += DEFSANDBOXCGROUPONLY_DB
|
||||
USER_VARS += DEFSANDBOXCGROUPONLY_FC
|
||||
USER_VARS += DEFSANDBOXCGROUPONLY_CLH
|
||||
USER_VARS += DEFENABLEVIRTIOMEM
|
||||
USER_VARS += DEFSANDBOXCGROUPONLY_REMOTE
|
||||
USER_VARS += DEFENABLEVCPUSPINNING_QEMU
|
||||
USER_VARS += DEFSTATICRESOURCEMGMT_DB
|
||||
|
||||
@@ -10,3 +10,7 @@ MACHINEACCELERATORS :=
|
||||
CPUFEATURES :=
|
||||
|
||||
QEMUCMD := qemu-system-s390x
|
||||
|
||||
# Enable virtio-mem for s390x
|
||||
DEFENABLEVIRTIOMEM = true
|
||||
|
||||
|
||||
@@ -167,8 +167,9 @@ memory_offset = 0
|
||||
# Specifies virtio-mem will be enabled or not.
|
||||
# Please note that this option should be used with the command
|
||||
# "echo 1 > /proc/sys/vm/overcommit_memory".
|
||||
# Default false
|
||||
enable_virtio_mem = false
|
||||
# Default is architecture/build dependent and is substituted from
|
||||
# @DEFENABLEVIRTIOMEM@ (for example, enabled on some builds such as s390x).
|
||||
enable_virtio_mem = @DEFENABLEVIRTIOMEM@
|
||||
|
||||
# Disable block device from being used for a container's rootfs.
|
||||
# In case of a storage driver like devicemapper where a container's
|
||||
|
||||
@@ -353,6 +353,196 @@ impl Qmp {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Cleanup virtio-mem resources on setup failure
|
||||
fn cleanup_virtio_mem_setup(&mut self, device_id: &str) {
|
||||
// Remove memory backend object
|
||||
let _ = self.qmp.execute(&qmp::object_del {
|
||||
id: "virtiomem".to_owned(),
|
||||
});
|
||||
|
||||
// Remove CCW device slot
|
||||
if let Some(ccw) = self.ccw_subchannel.as_mut() {
|
||||
ccw.remove_device(device_id).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_virtio_mem(
|
||||
&mut self,
|
||||
default_memory: u32,
|
||||
default_maxmemory: u32,
|
||||
machine_type: &str,
|
||||
shared_fs: Option<&str>,
|
||||
) -> Result<()> {
|
||||
// Calculate virtio-mem size: (default_maxmemory - default_memory) aligned to 4MB
|
||||
// default_maxmemory is already validated during sandbox initialization
|
||||
let diff_mb = default_maxmemory
|
||||
.checked_sub(default_memory)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"default_maxmemory ({}) must be >= default_memory ({}) for virtio-mem setup",
|
||||
default_maxmemory,
|
||||
default_memory
|
||||
)
|
||||
})?;
|
||||
let size_mb = u64::from(diff_mb & !3u32);
|
||||
|
||||
if size_mb == 0 {
|
||||
info!(sl!(), "virtio-mem size is 0, skipping setup");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Validate machine type for virtio-mem support
|
||||
// TODO: support more architectures
|
||||
if machine_type != "s390-ccw-virtio" {
|
||||
return Err(anyhow!(
|
||||
"virtio-mem supports multiple architectures, the current implementation is only for s390x (s390-ccw-virtio). Current machine type: {}",
|
||||
machine_type
|
||||
));
|
||||
}
|
||||
|
||||
// Determine memory backend based on shared filesystem
|
||||
let uses_virtio_fs = shared_fs
|
||||
.map(|fs| fs == "virtio-fs" || fs == "virtio-fs-nydus")
|
||||
.unwrap_or(false);
|
||||
|
||||
let (qomtype, mempath, share) = if uses_virtio_fs {
|
||||
("memory-backend-file", "/dev/shm", true)
|
||||
} else {
|
||||
("memory-backend-ram", "", false)
|
||||
};
|
||||
|
||||
let size_bytes = size_mb * 1024 * 1024;
|
||||
|
||||
// Allocate CCW slot and format address
|
||||
// Use same ID for both CCW subchannel tracking and QMP device
|
||||
let device_id = "virtiomem0";
|
||||
let ccw = self
|
||||
.ccw_subchannel
|
||||
.as_mut()
|
||||
.ok_or_else(|| anyhow!("CCW subchannel not initialized for s390x"))?;
|
||||
let slot = ccw
|
||||
.add_device(device_id)
|
||||
.map_err(|e| anyhow!("Failed to add CCW device: {:?}", e))?;
|
||||
let devno = ccw.address_format_ccw(slot);
|
||||
|
||||
info!(
|
||||
sl!(),
|
||||
"Setting up virtio-mem-ccw: backend={}, path={}, share={}, devno={}",
|
||||
qomtype,
|
||||
if mempath.is_empty() { "none" } else { mempath },
|
||||
share,
|
||||
devno
|
||||
);
|
||||
|
||||
// Helper to create common MemoryBackendProperties
|
||||
let create_backend_props = || qapi_qmp::MemoryBackendProperties {
|
||||
dump: None,
|
||||
host_nodes: None,
|
||||
merge: None,
|
||||
policy: None,
|
||||
prealloc: None,
|
||||
prealloc_context: None,
|
||||
prealloc_threads: None,
|
||||
reserve: None,
|
||||
share: Some(share),
|
||||
x_use_canonical_path_for_ramblock_id: None,
|
||||
size: size_bytes,
|
||||
};
|
||||
|
||||
// STEP 1: Create memory backend
|
||||
let memory_backend = if mempath.is_empty() {
|
||||
qmp::object_add(qapi_qmp::ObjectOptions::memory_backend_ram {
|
||||
id: "virtiomem".to_owned(),
|
||||
memory_backend_ram: create_backend_props(),
|
||||
})
|
||||
} else {
|
||||
qmp::object_add(qapi_qmp::ObjectOptions::memory_backend_file {
|
||||
id: "virtiomem".to_owned(),
|
||||
memory_backend_file: qapi_qmp::MemoryBackendFileProperties {
|
||||
base: create_backend_props(),
|
||||
align: None,
|
||||
discard_data: None,
|
||||
offset: None,
|
||||
pmem: None,
|
||||
readonly: None,
|
||||
rom: None,
|
||||
mem_path: mempath.to_owned(),
|
||||
},
|
||||
})
|
||||
};
|
||||
|
||||
// Execute backend creation with cleanup on error
|
||||
if let Err(e) = self.qmp.execute(&memory_backend) {
|
||||
self.cleanup_virtio_mem_setup(device_id);
|
||||
return if e.to_string().contains("Cannot allocate memory") {
|
||||
Err(anyhow!("Failed to allocate {} MB for virtio-mem: {}. \
|
||||
Please use command 'echo 1 > /proc/sys/vm/overcommit_memory' to handle it.",
|
||||
size_mb, e))
|
||||
} else {
|
||||
Err(e.into())
|
||||
};
|
||||
}
|
||||
|
||||
// STEP 2: Create virtio-mem-ccw device
|
||||
let mut device_args = Dictionary::new();
|
||||
device_args.insert("memdev".to_owned(), "virtiomem".into());
|
||||
device_args.insert("devno".to_owned(), devno.into());
|
||||
|
||||
if let Err(e) = self.qmp.execute(&qmp::device_add {
|
||||
bus: None,
|
||||
id: Some(device_id.to_owned()),
|
||||
driver: "virtio-mem-ccw".to_owned(),
|
||||
arguments: device_args,
|
||||
}) {
|
||||
self.cleanup_virtio_mem_setup(device_id);
|
||||
return Err(anyhow!("Failed to add virtio-mem-ccw device: {}", e));
|
||||
}
|
||||
|
||||
info!(
|
||||
sl!(),
|
||||
"Successfully set up virtio-mem-ccw with max capacity {} MB", size_mb
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resize virtio-mem device to the specified size in MB.
|
||||
/// This uses QMP qom-set to change the requested-size property.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `new_size_mb` - New size in MB for the virtio-mem device
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(())` on success
|
||||
/// * `Err` if resize fails or size is negative
|
||||
pub fn resize_virtio_mem(&mut self, new_size_mb: i64) -> Result<()> {
|
||||
// Validate and convert size from MB to bytes
|
||||
if new_size_mb < 0 {
|
||||
return Err(anyhow!(
|
||||
"cannot resize virtio-mem device to negative size ({}) memory",
|
||||
new_size_mb
|
||||
));
|
||||
}
|
||||
let size_bytes = (new_size_mb as u64) * 1024 * 1024;
|
||||
|
||||
info!(
|
||||
sl!(),
|
||||
"Resizing virtio-mem device to {} MB ({} bytes)", new_size_mb, size_bytes
|
||||
);
|
||||
|
||||
// Use qom-set to change the requested-size property of virtiomem0
|
||||
self.qmp.execute(&qmp::qom_set {
|
||||
path: "virtiomem0".to_owned(),
|
||||
property: "requested-size".to_owned(),
|
||||
value: serde_json::json!(size_bytes),
|
||||
})?;
|
||||
|
||||
info!(
|
||||
sl!(),
|
||||
"Successfully resized virtio-mem to {} MB", new_size_mb
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hotunplug_memory(&mut self, size: i64) -> Result<()> {
|
||||
let frontend = self
|
||||
.qmp
|
||||
|
||||
Reference in New Issue
Block a user