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)]
|
#[cfg(test)]
|
||||||
mod unit_tests {
|
mod unit_tests {
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
use virtio_queue::QueueT;
|
||||||
use vmm_sys_util::eventfd::EFD_NONBLOCK;
|
use vmm_sys_util::eventfd::EFD_NONBLOCK;
|
||||||
|
|
||||||
use super::*;
|
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;
|
struct NoopInterrupt;
|
||||||
impl VirtioInterrupt for NoopInterrupt {
|
impl VirtioInterrupt for NoopInterrupt {
|
||||||
fn trigger(&self, _: VirtioInterruptType) -> io::Result<()> {
|
fn trigger(&self, _: VirtioInterruptType) -> io::Result<()> {
|
||||||
@@ -616,6 +641,31 @@ mod unit_tests {
|
|||||||
assert_eq!(started.load(Ordering::SeqCst), 1);
|
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]
|
#[test]
|
||||||
fn reset_clears_paused_without_workers() {
|
fn reset_clears_paused_without_workers() {
|
||||||
// reset() before any worker was spawned must still clear paused, or
|
// reset() before any worker was spawned must still clear paused, or
|
||||||
|
|||||||
Reference in New Issue
Block a user