From 359468527922bf2dca9b3b85bc020019816a2604 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 14 Oct 2020 12:04:42 +0200 Subject: [PATCH] vmm: Move balloon code from MemoryManager to DeviceManager Now that we have a new dedicated way of asking for a balloon through the CLI and the REST API, we can move all the balloon code to the device manager. This allows us to simplify the memory manager, which is already quite complex. It also simplifies the behavior of the balloon resizing command. Instead of providing the expected size for the RAM, which is complex when memory zones are involved, it now expects the balloon size. This is a much more straightforward behavior as it really resizes the balloon to the desired size. Additionally to the simplication, the benefit of this approach is that it does not need to be tied to the memory manager at all. Signed-off-by: Sebastien Boeuf --- src/bin/ch-remote.rs | 6 +++--- vmm/src/api/mod.rs | 2 +- vmm/src/device_manager.rs | 40 +++++++++++++++++++++++++++++++++------ vmm/src/lib.rs | 8 ++++---- vmm/src/memory_manager.rs | 33 -------------------------------- vmm/src/vm.rs | 23 ++++++++++++---------- 6 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/bin/ch-remote.rs b/src/bin/ch-remote.rs index 3da594a8a..66cc69183 100644 --- a/src/bin/ch-remote.rs +++ b/src/bin/ch-remote.rs @@ -226,7 +226,7 @@ fn resize_api_command( None }; - let desired_ram_w_balloon: Option = if let Some(balloon) = balloon { + let desired_balloon: Option = if let Some(balloon) = balloon { Some( balloon .parse::() @@ -240,7 +240,7 @@ fn resize_api_command( let resize = vmm::api::VmResizeData { desired_vcpus, desired_ram, - desired_ram_w_balloon, + desired_balloon, }; simple_api_command( @@ -577,7 +577,7 @@ fn main() { .arg( Arg::with_name("balloon") .long("balloon") - .help("New memory with balloon size in bytes (supports K/M/G suffix)") + .help("New balloon size in bytes (supports K/M/G suffix)") .takes_value(true) .number_of_values(1), ), diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 8521954c8..36583f334 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -157,7 +157,7 @@ pub struct VmmPingResponse { pub struct VmResizeData { pub desired_vcpus: Option, pub desired_ram: Option, - pub desired_ram_w_balloon: Option, + pub desired_balloon: Option, } #[derive(Clone, Deserialize, Serialize, Default)] diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 85c6be252..51f5e2652 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -358,6 +358,12 @@ pub enum DeviceManagerError { /// No support for device passthrough NoDevicePassthroughSupport, + + /// Failed to resize virtio-balloon + VirtioBalloonResize(virtio_devices::balloon::Error), + + /// Missing virtio-balloon, can't proceed as expected. + MissingVirtioBalloon, } pub type DeviceManagerResult = result::Result; @@ -780,6 +786,9 @@ pub struct DeviceManager { // List of guest NUMA nodes. #[cfg(feature = "acpi")] numa_nodes: NumaNodes, + + // Possible handle to the virtio-balloon device + balloon: Option>>, } impl DeviceManager { @@ -850,6 +859,7 @@ impl DeviceManager { seccomp_action, #[cfg(feature = "acpi")] numa_nodes, + balloon: None, }; #[cfg(feature = "acpi")] @@ -2440,22 +2450,19 @@ impl DeviceManager { ) -> DeviceManagerResult> { let mut devices = Vec::new(); - if self.config.lock().unwrap().memory.balloon { + if let Some(balloon_config) = &self.config.lock().unwrap().balloon { let id = String::from(BALLOON_DEVICE_NAME); let virtio_balloon_device = Arc::new(Mutex::new( virtio_devices::Balloon::new( id.clone(), - self.config.lock().unwrap().memory.balloon_size, + balloon_config.size, self.seccomp_action.clone(), ) .map_err(DeviceManagerError::CreateVirtioBalloon)?, )); - self.memory_manager - .lock() - .unwrap() - .set_balloon(virtio_balloon_device.clone()); + self.balloon = Some(virtio_balloon_device.clone()); devices.push(( Arc::clone(&virtio_balloon_device) as VirtioDeviceArc, @@ -3197,6 +3204,27 @@ impl DeviceManager { counters } + + pub fn resize_balloon(&mut self, size: u64) -> DeviceManagerResult<()> { + if let Some(balloon) = &self.balloon { + return balloon + .lock() + .unwrap() + .resize(size) + .map_err(DeviceManagerError::VirtioBalloonResize); + } + + warn!("No balloon setup: Can't resize the balloon"); + Err(DeviceManagerError::MissingVirtioBalloon) + } + + pub fn balloon_size(&self) -> u64 { + if let Some(balloon) = &self.balloon { + return balloon.lock().unwrap().get_actual(); + } + + 0 + } } #[cfg(feature = "acpi")] diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 4ad9b8f45..5916b6a11 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -469,7 +469,7 @@ impl Vmm { let mut memory_actual_size = config.lock().unwrap().memory.total_size(); if let Some(vm) = &self.vm { - memory_actual_size -= vm.get_balloon_actual(); + memory_actual_size -= vm.balloon_size(); } Ok(VmInfo { @@ -511,10 +511,10 @@ impl Vmm { &mut self, desired_vcpus: Option, desired_ram: Option, - desired_ram_w_balloon: Option, + desired_balloon: Option, ) -> result::Result<(), VmError> { if let Some(ref mut vm) = self.vm { - if let Err(e) = vm.resize(desired_vcpus, desired_ram, desired_ram_w_balloon) { + if let Err(e) = vm.resize(desired_vcpus, desired_ram, desired_balloon) { error!("Error when resizing VM: {:?}", e); Err(e) } else { @@ -801,7 +801,7 @@ impl Vmm { .vm_resize( resize_data.desired_vcpus, resize_data.desired_ram, - resize_data.desired_ram_w_balloon, + resize_data.desired_balloon, ) .map_err(ApiError::VmResize) .map(|_| ApiResponsePayload::Empty); diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 61e686bb9..819c74c37 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -117,7 +117,6 @@ pub struct MemoryManager { snapshot: Mutex>>, shared: bool, hugepages: bool, - balloon: Option>>, #[cfg(target_arch = "x86_64")] sgx_epc_region: Option, user_provided_zones: bool, @@ -176,9 +175,6 @@ pub enum Error { /// memory regions. InvalidAmountExternalBackingFiles, - /// Failed to virtio-balloon resize - VirtioBalloonResizeFail(virtio_devices::balloon::Error), - /// Invalid SGX EPC section size #[cfg(target_arch = "x86_64")] EpcSectionSizeInvalid, @@ -688,7 +684,6 @@ impl MemoryManager { snapshot: Mutex::new(None), shared: config.shared, hugepages: config.hugepages, - balloon: None, #[cfg(target_arch = "x86_64")] sgx_epc_region: None, user_provided_zones, @@ -1085,10 +1080,6 @@ impl MemoryManager { Ok(region) } - pub fn set_balloon(&mut self, balloon: Arc>) { - self.balloon = Some(balloon); - } - pub fn guest_memory(&self) -> GuestMemoryAtomic { self.guest_memory.clone() } @@ -1242,30 +1233,6 @@ impl MemoryManager { Err(Error::UnknownMemoryZone) } - pub fn balloon_resize(&mut self, expected_ram: u64) -> Result { - let mut balloon_size = 0; - if let Some(balloon) = &self.balloon { - if expected_ram < self.current_ram { - balloon_size = self.current_ram - expected_ram; - } - balloon - .lock() - .unwrap() - .resize(balloon_size) - .map_err(Error::VirtioBalloonResizeFail)?; - } - - Ok(balloon_size) - } - - pub fn get_balloon_actual(&self) -> u64 { - if let Some(balloon) = &self.balloon { - return balloon.lock().unwrap().get_actual(); - } - - 0 - } - /// In case this function resulted in adding a new memory region to the /// guest memory, the new region is returned to the caller. The virtio-mem /// use case never adds a new region as the whole hotpluggable memory has diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 60155ac0a..12c61b590 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -1040,7 +1040,7 @@ impl Vm { &mut self, desired_vcpus: Option, desired_memory: Option, - desired_ram_w_balloon: Option, + desired_balloon: Option, ) -> Result<()> { if let Some(desired_vcpus) = desired_vcpus { if self @@ -1103,15 +1103,18 @@ impl Vm { } } - if let Some(desired_ram_w_balloon) = desired_ram_w_balloon { - // update the configuration value for the balloon size to ensure - // a reboot would use the right value. - self.config.lock().unwrap().memory.balloon_size = self - .memory_manager + if let Some(desired_balloon) = desired_balloon { + self.device_manager .lock() .unwrap() - .balloon_resize(desired_ram_w_balloon) - .map_err(Error::MemoryManager)?; + .resize_balloon(desired_balloon) + .map_err(Error::DeviceManager)?; + + // Update the configuration value for the balloon size to ensure + // a reboot would use the right value. + if let Some(balloon_config) = &mut self.config.lock().unwrap().balloon { + balloon_config.size = desired_balloon; + } } Ok(()) @@ -1607,8 +1610,8 @@ impl Vm { } /// Gets the actual size of the balloon. - pub fn get_balloon_actual(&self) -> u64 { - self.memory_manager.lock().unwrap().get_balloon_actual() + pub fn balloon_size(&self) -> u64 { + self.device_manager.lock().unwrap().balloon_size() } }