diff --git a/virtio-devices/src/device.rs b/virtio-devices/src/device.rs index 57248eb6e..648466a3b 100644 --- a/virtio-devices/src/device.rs +++ b/virtio-devices/src/device.rs @@ -516,12 +516,37 @@ impl Pausable for VirtioCommon { #[cfg(test)] mod unit_tests { + use std::sync::Mutex; use std::sync::atomic::{AtomicUsize, Ordering}; + use virtio_queue::QueueT; use vmm_sys_util::eventfd::EFD_NONBLOCK; use super::*; + #[derive(Default)] + struct RecordingInterrupt { + queue_indices: Mutex>, + } + + impl VirtioInterrupt for RecordingInterrupt { + fn trigger(&self, int_type: VirtioInterruptType) -> io::Result<()> { + if let VirtioInterruptType::Queue(queue_index) = int_type { + self.queue_indices.lock().unwrap().push(queue_index); + } + Ok(()) + } + + fn set_notifier( + &self, + _: u32, + _: Option, + _: &dyn hypervisor::Vm, + ) -> io::Result<()> { + Ok(()) + } + } + struct NoopInterrupt; impl VirtioInterrupt for NoopInterrupt { fn trigger(&self, _: VirtioInterruptType) -> io::Result<()> { @@ -616,6 +641,31 @@ mod unit_tests { assert_eq!(started.load(Ordering::SeqCst), 1); } + #[test] + fn resume_preserves_sparse_queue_indices() { + let interrupt = Arc::new(RecordingInterrupt::default()); + let queues = vec![ + ( + 1, + Queue::new(256).unwrap(), + EventFd::new(EFD_NONBLOCK).unwrap(), + ), + ( + 3, + Queue::new(256).unwrap(), + EventFd::new(EFD_NONBLOCK).unwrap(), + ), + ]; + let mut common = VirtioCommon::default(); + + common.activate(&queues, interrupt.clone()).unwrap(); + common.resume().unwrap(); + + assert_eq!(queues[0].2.read().unwrap(), 1); + assert_eq!(queues[1].2.read().unwrap(), 1); + assert_eq!(*interrupt.queue_indices.lock().unwrap(), vec![1, 3]); + } + #[test] fn reset_clears_paused_without_workers() { // reset() before any worker was spawned must still clear paused, or