mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: vmm: Signal NEEDS_RESET on activation failure
When the guest writes DRIVER_OK and the device fails to activate, the VMM previously bubbled the error up via VirtioActivate and never released the activation barrier, leaving the vCPU that wrote DRIVER_OK blocked on the barrier and effectively deadlocking the guest. Per virtio 1.3 section 2.1.2, a device that has experienced an error it cannot recover from should set DEVICE_NEEDS_RESET in its status and notify the driver via a configuration change interrupt. Do that on activation failure through the existing mark_device_needs_reset helper, then release the activation barrier so the vCPU can resume. DeviceManager::activate_virtio_devices now logs and continues instead of aborting the whole pending list, so one failing device does not take down the VMM or block pause and migration. The activator has already reported the failure with the device id. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
d92e1ea77b
commit
2d2931a76e
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user