mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: Test sparse queue indices on resume
Filtered activation queues can hide regressions where resume treats their positions as transport queue indices. Such regressions route interrupts to unrelated MSI-X vectors while eventfd notifications still reach the correct workers. Add a VirtioCommon regression test with queue indices one and three. Verify resume signals both queue eventfds and records interrupts for the original sparse indices. Assisted-by: OpenAI:GPT-5.6-Sol Signed-off-by: Yi Wang <foxywang@tencent.com>
This commit is contained in:
@@ -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<Vec<u16>>,
|
||||
}
|
||||
|
||||
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<EventFd>,
|
||||
_: &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
|
||||
|
||||
Reference in New Issue
Block a user