diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs index b91856e59..44c69d209 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs @@ -1365,6 +1365,7 @@ mod unit_tests { use vm_device::interrupt::InterruptSourceConfig; use super::*; + use crate::{ActivateError, DEVICE_NEEDS_RESET}; struct TestInterruptSourceGroup { event_fd: EventFd, @@ -1594,4 +1595,30 @@ mod unit_tests { }; (activator, status, device_activated, interrupt, barrier) } + + #[test] + fn activate_failure_marks_needs_reset_and_releases_barrier() { + let (activator, status, device_activated, interrupt, barrier) = + make_activator(Err(ActivateError::BadActivate)); + + // Simulate the vCPU thread blocked on the activation + // barrier after writing DRIVER_OK. + let waiter = std::thread::spawn(move || barrier.wait()); + + let result = activator.activate(); + + assert!(matches!(result, Err(ActivateError::BadActivate))); + assert!(!device_activated.load(Ordering::SeqCst)); + assert_ne!( + status.load(Ordering::SeqCst) & (DEVICE_NEEDS_RESET as u8), + 0 + ); + let triggers = interrupt.triggers.lock().unwrap(); + assert_eq!(triggers.len(), 1); + assert!(matches!(triggers[0], VirtioInterruptType::Config)); + + // The barrier waiter must complete, showing the activator + // did not deadlock the vCPU thread. + waiter.join().expect("barrier waiter deadlocked"); + } }