From 69bd0036d906ac456c285d667496e5a9922db229 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Mon, 10 Jul 2023 08:53:34 +0000 Subject: [PATCH] vmm: support removing devices before VM is booted If the VM has been configured but not yet booted, all we need to do to support removing a device is to remove it from the config, so it will never be created. Signed-off-by: Alyssa Ross --- vmm/src/config.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++ vmm/src/lib.rs | 11 +++++++-- vmm/src/vm.rs | 47 +++-------------------------------- 3 files changed, 76 insertions(+), 45 deletions(-) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 9506fed99..ecb8493af 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -2101,6 +2101,69 @@ impl VmConfig { Ok(config) } + pub fn remove_device(&mut self, id: &str) -> bool { + let mut removed = false; + + // Remove if VFIO device + if let Some(devices) = self.devices.as_mut() { + let len = devices.len(); + devices.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= devices.len() != len; + } + + // Remove if VFIO user device + if let Some(user_devices) = self.user_devices.as_mut() { + let len = user_devices.len(); + user_devices.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= user_devices.len() != len; + } + + // Remove if disk device + if let Some(disks) = self.disks.as_mut() { + let len = disks.len(); + disks.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= disks.len() != len; + } + + // Remove if fs device + if let Some(fs) = self.fs.as_mut() { + let len = fs.len(); + fs.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= fs.len() != len; + } + + // Remove if net device + if let Some(net) = self.net.as_mut() { + let len = net.len(); + net.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= net.len() != len; + } + + // Remove if pmem device + if let Some(pmem) = self.pmem.as_mut() { + let len = pmem.len(); + pmem.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= pmem.len() != len; + } + + // Remove if vDPA device + if let Some(vdpa) = self.vdpa.as_mut() { + let len = vdpa.len(); + vdpa.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= vdpa.len() != len; + } + + // Remove if vsock device + if let Some(vsock) = self.vsock.as_ref() { + if vsock.id.as_ref().map(|id| id.as_ref()) == Some(id) { + self.vsock = None; + removed = true; + } + } + + removed + } + /// # Safety /// To use this safely, the caller must guarantee that the input /// fds are all valid. diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 264037a9d..523cc1023 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -1025,13 +1025,20 @@ impl Vmm { fn vm_remove_device(&mut self, id: String) -> result::Result<(), VmError> { if let Some(ref mut vm) = self.vm { if let Err(e) = vm.remove_device(id) { - error!("Error when removing new device to the VM: {:?}", e); + error!("Error when removing device from the VM: {:?}", e); Err(e) } else { Ok(()) } + } else if let Some(ref config) = self.vm_config { + let mut config = config.lock().unwrap(); + if config.remove_device(&id) { + Ok(()) + } else { + Err(VmError::NoDeviceToRemove(id)) + } } else { - Err(VmError::VmNotRunning) + Err(VmError::VmNotCreated) } } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 790c9c332..f28fcd668 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -137,6 +137,9 @@ pub enum Error { #[error("Error from device manager: {0:?}")] DeviceManager(DeviceManagerError), + #[error("No device with id {0:?} to remove")] + NoDeviceToRemove(String), + #[error("Cannot spawn a signal handler thread: {0}")] SignalHandlerSpawn(#[source] io::Error), @@ -1406,49 +1409,7 @@ impl Vm { // Update VmConfig by removing the device. This is important to // ensure the device would not be created in case of a reboot. - let mut config = self.config.lock().unwrap(); - - // Remove if VFIO device - if let Some(devices) = config.devices.as_mut() { - devices.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if VFIO user device - if let Some(user_devices) = config.user_devices.as_mut() { - user_devices.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if disk device - if let Some(disks) = config.disks.as_mut() { - disks.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if fs device - if let Some(fs) = config.fs.as_mut() { - fs.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if net device - if let Some(net) = config.net.as_mut() { - net.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if pmem device - if let Some(pmem) = config.pmem.as_mut() { - pmem.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if vDPA device - if let Some(vdpa) = config.vdpa.as_mut() { - vdpa.retain(|dev| dev.id.as_ref() != Some(&id)); - } - - // Remove if vsock device - if let Some(vsock) = config.vsock.as_ref() { - if vsock.id.as_ref() == Some(&id) { - config.vsock = None; - } - } + self.config.lock().unwrap().remove_device(&id); self.device_manager .lock()