diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs index dedd8a5d22..a31fb481cc 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs @@ -19,6 +19,7 @@ use kata_types::{ use persist::sandbox_persist::Persist; use std::cmp::Ordering; use std::collections::HashMap; +use std::convert::TryInto; use std::path::Path; use std::process::Stdio; use tokio::{ @@ -467,6 +468,18 @@ impl QemuInner { "hotunplugging {} B of memory", cur_hotplugged_memory - new_hotplugged_mem ); + let res = + qmp.hotunplug_memory((cur_hotplugged_memory - new_hotplugged_mem).try_into()?); + if let Err(err) = res { + info!(sl!(), "hotunplugging failed: {:?}", err); + } else { + new_total_mem_mb = bytes_to_megs(coldplugged_mem + new_hotplugged_mem); + } + info!( + sl!(), + "hotplugged memory after hotunplugging: {}", + qmp.hotplugged_memory_size()? + ); } Ordering::Equal => info!( sl!(), diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs index 95ad212bad..7339efdf8b 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use anyhow::Result; +use anyhow::{anyhow, Result}; use std::fmt::{Debug, Error, Formatter}; use std::io::BufReader; use std::os::unix::net::UnixStream; @@ -235,6 +235,62 @@ impl Qmp { Ok(()) } + + pub fn hotunplug_memory(&mut self, size: i64) -> Result<()> { + let frontend = self + .qmp + .execute(&qapi_qmp::query_memory_devices {})? + .into_iter() + .find(|memdev| { + if let qapi_qmp::MemoryDeviceInfo::dimm(dimm_info) = memdev { + let dimm_id = match dimm_info.data.id { + Some(ref id) => id, + None => return false, + }; + if dimm_info.data.hotpluggable + && dimm_info.data.hotplugged + && dimm_info.data.size == size + && dimm_id.starts_with("frontend-to-hotplugged-") + { + return true; + } + } + false + }); + + if let Some(frontend) = frontend { + if let qapi_qmp::MemoryDeviceInfo::dimm(frontend) = frontend { + info!(sl!(), "found frontend to hotunplug: {:#?}", frontend); + + let frontend_id = match frontend.data.id { + Some(id) => id, + // This shouldn't happen as it was checked by find() above already. + None => return Err(anyhow!("memory frontend to hotunplug has empty id")), + }; + + let backend_id = match frontend_id.strip_prefix("frontend-to-") { + Some(id) => id.to_owned(), + // This shouldn't happen as it was checked by find() above already. + None => { + return Err(anyhow!( + "memory backend to hotunplug has id that doesn't have the expected prefix" + )) + } + }; + + self.qmp.execute(&qmp::device_del { id: frontend_id })?; + self.qmp.execute(&qmp::object_del { id: backend_id })?; + } else { + // This shouldn't happen as it was checked by find() above already. + return Err(anyhow!("memory device to hotunplug is not a dimm")); + } + } else { + return Err(anyhow!( + "couldn't find a suitable memory device to hotunplug" + )); + } + Ok(()) + } } fn vcpu_id_from_core_id(core_id: i64) -> String {