runtime-rs: add experimental support for memory hotunplugging to qemu-rs

Hotunplugging memory is not guaranteed or even likely to work.
Nevertheless I'd really like to have this code in for tests and
observation.  It shouldn't hurt, from experience so far.

Signed-off-by: Pavel Mores <pmores@redhat.com>
This commit is contained in:
Pavel Mores 2024-07-04 16:36:16 +02:00 committed by Pavel Mores
parent 3095b65ac3
commit dd1e09bd9d
2 changed files with 70 additions and 1 deletions

View File

@ -19,6 +19,7 @@ use kata_types::{
use persist::sandbox_persist::Persist; use persist::sandbox_persist::Persist;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto;
use std::path::Path; use std::path::Path;
use std::process::Stdio; use std::process::Stdio;
use tokio::{ use tokio::{
@ -467,6 +468,18 @@ impl QemuInner {
"hotunplugging {} B of memory", "hotunplugging {} B of memory",
cur_hotplugged_memory - new_hotplugged_mem 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!( Ordering::Equal => info!(
sl!(), sl!(),

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use anyhow::Result; use anyhow::{anyhow, Result};
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::io::BufReader; use std::io::BufReader;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
@ -235,6 +235,62 @@ impl Qmp {
Ok(()) 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 { fn vcpu_id_from_core_id(core_id: i64) -> String {