vmm: Update memory configuration upon virtio-mem resizing

Based on all the preparatory work achieved through previous commits,
this patch updates the 'hotplugged_size' field for both MemoryConfig and
MemoryZoneConfig structures when either the whole memory is resized, or
simply when a memory zone is resized.

This fixes the lack of support for rebooting a VM with the right amount
of memory plugged in.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2020-09-14 23:50:30 +02:00
parent de2b917f55
commit 1e1a50ef70
2 changed files with 52 additions and 34 deletions

View File

@ -664,8 +664,8 @@ impl MemoryManager {
mergeable: config.mergeable,
allocator: allocator.clone(),
hotplug_method: config.hotplug_method.clone(),
boot_ram: config.size,
current_ram: config.size,
boot_ram: ram_size,
current_ram: ram_size,
next_hotplug_slot: 0,
snapshot: Mutex::new(None),
shared: config.shared,
@ -1268,12 +1268,7 @@ impl MemoryManager {
Ok(region)
}
pub fn resize_zone(
&mut self,
id: &str,
desired_ram: u64,
config: &MemoryConfig,
) -> Result<(), Error> {
pub fn resize_zone(&mut self, id: &str, virtio_mem_size: u64) -> Result<(), Error> {
if !self.user_provided_zones {
error!(
"Not allowed to resize guest memory zone when no zone is \
@ -1282,25 +1277,7 @@ impl MemoryManager {
return Err(Error::ResizeZone);
}
if let Some(zones) = &config.zones {
for zone in zones.iter() {
if zone.id == id {
if desired_ram >= zone.size {
return self.virtio_mem_resize(id, desired_ram - zone.size);
} else {
error!(
"Invalid to ask less ({}) than boot RAM ({}) for \
this memory zone",
desired_ram, zone.size,
);
return Err(Error::ResizeZone);
}
}
}
}
error!("Could not find the memory zone {} for the resize", id);
Err(Error::ResizeZone)
self.virtio_mem_resize(id, virtio_mem_size)
}
#[cfg(target_arch = "x86_64")]

View File

@ -209,6 +209,9 @@ pub enum Error {
/// Cannot apply seccomp filter
ApplySeccompFilter(seccomp::Error),
/// Failed resizing a memory zone.
ResizeZone,
}
pub type Result<T> = result::Result<T, Error>;
@ -884,6 +887,8 @@ impl Vm {
.resize(desired_memory)
.map_err(Error::MemoryManager)?;
let mut memory_config = &mut self.config.lock().unwrap().memory;
if let Some(new_region) = &new_region {
self.device_manager
.lock()
@ -891,7 +896,6 @@ impl Vm {
.update_memory(&new_region)
.map_err(Error::DeviceManager)?;
let memory_config = &self.config.lock().unwrap().memory;
match memory_config.hotplug_method {
HotplugMethod::Acpi => {
self.device_manager
@ -907,7 +911,16 @@ impl Vm {
// We update the VM config regardless of the actual guest resize
// operation result (happened or not), so that if the VM reboots
// it will be running with the last configure memory size.
self.config.lock().unwrap().memory.size = desired_memory;
match memory_config.hotplug_method {
HotplugMethod::Acpi => memory_config.size = desired_memory,
HotplugMethod::VirtioMem => {
if desired_memory > memory_config.size {
memory_config.hotplugged_size = Some(desired_memory - memory_config.size);
} else {
memory_config.hotplugged_size = None;
}
}
}
}
if let Some(desired_ram_w_balloon) = desired_ram_w_balloon {
@ -925,11 +938,39 @@ impl Vm {
}
pub fn resize_zone(&mut self, id: String, desired_memory: u64) -> Result<()> {
let memory_config = &mut self.config.lock().unwrap().memory;
if let Some(zones) = &mut memory_config.zones {
for zone in zones.iter_mut() {
if zone.id == id {
if desired_memory >= zone.size {
let hotplugged_size = desired_memory - zone.size;
self.memory_manager
.lock()
.unwrap()
.resize_zone(&id, desired_memory, &self.config.lock().unwrap().memory)
.map_err(Error::MemoryManager)
.resize_zone(&id, desired_memory - zone.size)
.map_err(Error::MemoryManager)?;
// We update the memory zone config regardless of the
// actual 'resize-zone' operation result (happened or
// not), so that if the VM reboots it will be running
// with the last configured memory zone size.
zone.hotplugged_size = Some(hotplugged_size);
return Ok(());
} else {
error!(
"Invalid to ask less ({}) than boot RAM ({}) for \
this memory zone",
desired_memory, zone.size,
);
return Err(Error::ResizeZone);
}
}
}
}
error!("Could not find the memory zone {} for the resize", id);
Err(Error::ResizeZone)
}
#[cfg(not(feature = "pci_support"))]