mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
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 <hi@alyssa.is>
This commit is contained in:
parent
87d81dd2b1
commit
69bd0036d9
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user