From 64c552cc96ace3da613292095d7f2f12cf48ddc0 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Wed, 27 May 2026 09:29:51 +0200 Subject: [PATCH] virtio-devices: Test activator failure releases barrier Feed BadActivate into VirtioPciDeviceActivator and assert that the error propagates, device_activated stays false, DEVICE_NEEDS_RESET is set in status, a single Config interrupt is delivered, and a thread waiting on the activation barrier unblocks. The barrier release is the deadlock fixed by the NEEDS_RESET on activation failure change. Assisted-by: Claude:Opus-4.7 Signed-off-by: Anatol Belski --- virtio-devices/src/transport/pci_device.rs | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) 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"); + } }