diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs index 50c83d11a..db6fe517b 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs @@ -40,9 +40,9 @@ use vmm_sys_util::eventfd::EventFd; use super::pci_common_config::VirtioPciCommonConfigState; use crate::transport::{VIRTIO_PCI_COMMON_CONFIG_ID, VirtioPciCommonConfig, VirtioTransport}; use crate::{ - ActivateResult, DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, DEVICE_FAILED, - DEVICE_FEATURES_OK, DEVICE_INIT, GuestMemoryMmap, VirtioDevice, VirtioDeviceType, - VirtioInterrupt, VirtioInterruptType, + ActivateResult, ActivationContext, DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, + DEVICE_FAILED, DEVICE_FEATURES_OK, DEVICE_INIT, GuestMemoryMmap, VirtioDevice, + VirtioDeviceType, VirtioInterrupt, VirtioInterruptType, mark_device_needs_reset, }; /// Vector value used to disable MSI for a queue. @@ -331,22 +331,32 @@ pub struct VirtioPciDeviceActivator { impl VirtioPciDeviceActivator { pub fn activate(mut self) -> ActivateResult { - let mut locked_device = self.device.lock().unwrap(); - locked_device.activate(crate::device::ActivationContext { + let result = self.device.lock().unwrap().activate(ActivationContext { mem: self.memory.take().unwrap(), - interrupt_cb: self.interrupt, + interrupt_cb: self.interrupt.clone(), queues: self.queues.take().unwrap(), - device_status: self.status, - })?; - self.device_activated.store(true, Ordering::SeqCst); + device_status: self.status.clone(), + }); + if let Err(e) = &result { + mark_device_needs_reset( + &self.status, + self.interrupt.as_ref(), + format_args!("{}: virtio device activation failed: {e:?}", self.id), + ); + } else { + self.device_activated.store(true, Ordering::SeqCst); + } + + // Release the barrier regardless of outcome. A failing activate() + // would otherwise deadlock the vCPU that wrote DRIVER_OK. if let Some(barrier) = self.barrier.take() { info!("{}: Waiting for barrier", self.id); barrier.wait(); info!("{}: Barrier released", self.id); } - Ok(()) + result } } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 5c6056d11..b1b8352d0 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -88,8 +88,7 @@ use vfio_ioctls::{VfioContainer, VfioDevice, VfioDeviceFd, VfioOps}; use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, VirtioTransport}; use virtio_devices::vhost_user::VhostUserConfig; use virtio_devices::{ - AccessPlatformMapping, ActivateError, Block, Endpoint, IommuMapping, VdpaDmaMapping, - VirtioMemMappingSource, + AccessPlatformMapping, Block, Endpoint, IommuMapping, VdpaDmaMapping, VirtioMemMappingSource, }; use vm_allocator::{AddressAllocator, InterruptAllocError, SystemAllocator}; use vm_device::dma_mapping::ExternalDmaMapping; @@ -629,10 +628,6 @@ pub enum DeviceManagerError { #[error("vfio-user socket path already in use: {0:?}")] UserDeviceSocketInUse(std::path::PathBuf), - /// Error activating virtio device - #[error("Error activating virtio device")] - VirtioActivate(#[source] ActivateError), - /// Failed retrieving device state from snapshot #[error("Failed retrieving device state from snapshot")] RestoreGetState(#[source] MigratableError), @@ -4699,9 +4694,9 @@ impl DeviceManager { pub fn activate_virtio_devices(&self) -> DeviceManagerResult<()> { for activator in self.pending_activations.lock().unwrap().drain(..) { - activator - .activate() - .map_err(DeviceManagerError::VirtioActivate)?; + // Failures are logged and signalled to the guest via + // NEEDS_RESET by the activator, hence keep going. + let _ = activator.activate(); } Ok(()) }