From c1f1fe713f0ab3731bacb6efbb9b2b13909c4aec Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 13 May 2019 18:12:40 -0700 Subject: [PATCH] vm: Propagate errors appropriately In order to get meaningful error messages, we want to make sure all errors are passed up the call stack. This patch fixes this previous limitation by separating errors related to the DeviceManager from errors related to the Vm. Signed-off-by: Sebastien Boeuf --- vmm/src/vm.rs | 117 +++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 5c79f508b..cfa421e77 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -112,12 +112,12 @@ pub enum Error { /// The call to KVM_SET_CPUID2 failed. SetSupportedCpusFailed(io::Error), + /// Cannot create a device manager. + DeviceManager(DeviceManagerError), + /// Cannot create EventFd. EventFd(io::Error), - /// Cannot create a device manager. - DeviceManager, - /// Cannot add legacy device to Bus. BusError(devices::BusError), @@ -133,23 +133,22 @@ pub enum Error { /// Cannot setup terminal in canonical mode. SetTerminalCanon(vmm_sys_util::Error), - /// Cannot allocate IRQ. - AllocateIrq, - - /// Cannot allocate PCI BARs - AllocateBars(pci::PciDeviceError), - - /// Cannot register ioevent. - RegisterIoevent(io::Error), - /// Cannot configure the IRQ. Irq(io::Error), - /// Cannot create virtio device - VirtioDevice, + /// Cannot create the system allocator + CreateSystemAllocator, - /// Cannot add PCI device - AddPciDevice(pci::PciRootError), + /// Failed parsing network parameters + ParseNetworkParameters, +} +pub type Result = result::Result; + +/// Errors associated with device manager +#[derive(Debug)] +pub enum DeviceManagerError { + /// Cannot create EventFd. + EventFd(io::Error), /// Cannot open disk path Disk(io::Error), @@ -163,22 +162,34 @@ pub enum Error { /// Cannot create virtio-rng device CreateVirtioRng(io::Error), - /// Cannot create the system allocator - CreateSystemAllocator, - - /// Failed parsing network parameters - ParseNetworkParameters, - - /// Cannot open tap interface - OpenTap(net_util::TapError), - /// Failed parsing disk image format DetectImageType(qcow::Error), /// Cannot open qcow disk path QcowDeviceCreate(qcow::Error), + + /// Cannot open tap interface + OpenTap(net_util::TapError), + + /// Cannot allocate IRQ. + AllocateIrq, + + /// Cannot configure the IRQ. + Irq(io::Error), + + /// Cannot allocate PCI BARs + AllocateBars(pci::PciDeviceError), + + /// Cannot register ioevent. + RegisterIoevent(io::Error), + + /// Cannot create virtio device + VirtioDevice(vmm_sys_util::Error), + + /// Cannot add PCI device + AddPciDevice(pci::PciRootError), } -pub type Result = result::Result; +pub type DeviceManagerResult = result::Result; /// A wrapper around creating and using a kvm-based VCPU. pub struct Vcpu { @@ -350,18 +361,20 @@ impl DeviceManager { allocator: &mut SystemAllocator, vm_fd: &VmFd, vm_cfg: &VmConfig, - ) -> Result { + ) -> DeviceManagerResult { let io_bus = devices::Bus::new(); let mut mmio_bus = devices::Bus::new(); - let serial_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?; + let serial_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?; let serial = Arc::new(Mutex::new(devices::legacy::Serial::new_out( - serial_evt.try_clone().map_err(Error::EventFd)?, + serial_evt + .try_clone() + .map_err(DeviceManagerError::EventFd)?, Box::new(stdout()), ))); - let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?; + let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?; let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new( - exit_evt.try_clone().map_err(Error::EventFd)?, + exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?, ))); let mut pci_root = PciRoot::new(None); @@ -371,22 +384,24 @@ impl DeviceManager { .read(true) .write(true) .open(&vm_cfg.disk_path) - .map_err(Error::Disk)?; + .map_err(DeviceManagerError::Disk)?; // Add virtio-blk - let image_type = qcow::detect_image_type(&raw_img).map_err(Error::DetectImageType)?; + let image_type = + qcow::detect_image_type(&raw_img).map_err(DeviceManagerError::DetectImageType)?; let disk_path = vm_cfg.disk_path.to_path_buf(); let block = match image_type { ImageType::Raw => { let raw_img = vm_virtio::RawFile::new(raw_img); let dev = vm_virtio::Block::new(raw_img, disk_path, false) - .map_err(Error::CreateVirtioBlock)?; + .map_err(DeviceManagerError::CreateVirtioBlock)?; Box::new(dev) as Box } ImageType::Qcow2 => { - let qcow_img = QcowFile::from(raw_img).map_err(Error::QcowDeviceCreate)?; + let qcow_img = + QcowFile::from(raw_img).map_err(DeviceManagerError::QcowDeviceCreate)?; let dev = vm_virtio::Block::new(qcow_img, disk_path, false) - .map_err(Error::CreateVirtioBlock)?; + .map_err(DeviceManagerError::CreateVirtioBlock)?; Box::new(dev) as Box } }; @@ -406,17 +421,17 @@ impl DeviceManager { let mut virtio_net_device: vm_virtio::Net; if let Some(tap_if_name) = net_params.tap_if_name { - let tap = Tap::open_named(tap_if_name).map_err(Error::OpenTap)?; + let tap = Tap::open_named(tap_if_name).map_err(DeviceManagerError::OpenTap)?; virtio_net_device = vm_virtio::Net::new_with_tap(tap, Some(&net_params.mac_addr)) - .map_err(Error::CreateVirtioNet)?; + .map_err(DeviceManagerError::CreateVirtioNet)?; } else { virtio_net_device = vm_virtio::Net::new( net_params.ip_addr, net_params.net_mask, Some(&net_params.mac_addr), ) - .map_err(Error::CreateVirtioNet)?; + .map_err(DeviceManagerError::CreateVirtioNet)?; } DeviceManager::add_virtio_pci_device( @@ -433,7 +448,7 @@ impl DeviceManager { // Add virtio-rng if required if let Some(rng_path) = &vm_cfg.rng_path { let virtio_rng_device = - vm_virtio::Rng::new(rng_path).map_err(Error::CreateVirtioRng)?; + vm_virtio::Rng::new(rng_path).map_err(DeviceManagerError::CreateVirtioRng)?; DeviceManager::add_virtio_pci_device( Box::new(virtio_rng_device), @@ -465,26 +480,28 @@ impl DeviceManager { vm_fd: &VmFd, pci_root: &mut PciRoot, mmio_bus: &mut devices::Bus, - ) -> Result<()> { - let mut virtio_pci_device = - VirtioPciDevice::new(memory, virtio_device).map_err(|_| Error::VirtioDevice)?; + ) -> DeviceManagerResult<()> { + let mut virtio_pci_device = VirtioPciDevice::new(memory, virtio_device) + .map_err(DeviceManagerError::VirtioDevice)?; let bars = virtio_pci_device .allocate_bars(allocator) - .map_err(Error::AllocateBars)?; + .map_err(DeviceManagerError::AllocateBars)?; for (event, addr, _) in virtio_pci_device.ioeventfds() { let io_addr = IoEventAddress::Mmio(addr); vm_fd .register_ioevent(event.as_raw_fd(), &io_addr, NoDatamatch) - .map_err(Error::RegisterIoevent)?; + .map_err(DeviceManagerError::RegisterIoevent)?; } // Assign IRQ to the virtio-pci device - let irqfd = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?; - let irq_num = allocator.allocate_irq().ok_or(Error::AllocateIrq)?; + let irqfd = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?; + let irq_num = allocator + .allocate_irq() + .ok_or(DeviceManagerError::AllocateIrq)?; vm_fd .register_irqfd(irqfd.as_raw_fd(), irq_num) - .map_err(Error::Irq)?; + .map_err(DeviceManagerError::Irq)?; // Let's use irq line INTA for now. virtio_pci_device.assign_irq(irqfd, irq_num as u32, PciInterruptPin::IntA); @@ -492,7 +509,7 @@ impl DeviceManager { pci_root .add_device(virtio_pci_device.clone(), mmio_bus, bars) - .map_err(Error::AddPciDevice)?; + .map_err(DeviceManagerError::AddPciDevice)?; Ok(()) } @@ -646,7 +663,7 @@ impl<'a> Vm<'a> { .ok_or(Error::CreateSystemAllocator)?; let device_manager = DeviceManager::new(guest_memory.clone(), &mut allocator, &fd, &config) - .map_err(|_| Error::DeviceManager)?; + .map_err(Error::DeviceManager)?; fd.register_irqfd(device_manager.serial_evt.as_raw_fd(), 4) .map_err(Error::Irq)?;