From 1e1a50ef705d1af10972fdccdcc7341c82902845 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 14 Sep 2020 23:50:30 +0200 Subject: [PATCH] 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 --- vmm/src/memory_manager.rs | 31 +++------------------- vmm/src/vm.rs | 55 ++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 95b589009..11f27dd52 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -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")] diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 29217a196..a4f5be344 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -209,6 +209,9 @@ pub enum Error { /// Cannot apply seccomp filter ApplySeccompFilter(seccomp::Error), + + /// Failed resizing a memory zone. + ResizeZone, } pub type Result = result::Result; @@ -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<()> { - self.memory_manager - .lock() - .unwrap() - .resize_zone(&id, desired_memory, &self.config.lock().unwrap().memory) - .map_err(Error::MemoryManager) + 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 - 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"))]