Skip to content

Commit 53338f7

Browse files
committed
test: ensure virtio device activation failure is handled correctly
Add a unittest to deal with the case where virtio device activation fails. In this case, the device state needs to be put to DEVICE_NEEDS_RESET, and an interrupt should have been generated. Signed-off-by: Patrick Roy <[email protected]>
1 parent 297db95 commit 53338f7

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

src/vmm/src/devices/virtio/mmio.rs

+65-1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ pub(crate) mod tests {
377377

378378
use super::*;
379379
use crate::devices::virtio::device::IrqTrigger;
380+
use crate::devices::virtio::device_status::DEVICE_NEEDS_RESET;
380381
use crate::devices::virtio::ActivateError;
381382
use crate::utilities::test_utils::single_region_mem;
382383
use crate::vstate::memory::GuestMemoryMmap;
@@ -390,6 +391,7 @@ pub(crate) mod tests {
390391
queues: Vec<Queue>,
391392
device_activated: bool,
392393
config_bytes: [u8; 0xeff],
394+
activate_should_error: bool,
393395
}
394396

395397
impl DummyDevice {
@@ -405,6 +407,7 @@ pub(crate) mod tests {
405407
queues: vec![Queue::new(16), Queue::new(32)],
406408
device_activated: false,
407409
config_bytes: [0; 0xeff],
410+
activate_should_error: false,
408411
}
409412
}
410413

@@ -458,7 +461,11 @@ pub(crate) mod tests {
458461

459462
fn activate(&mut self, _: GuestMemoryMmap) -> Result<(), ActivateError> {
460463
self.device_activated = true;
461-
Ok(())
464+
if self.activate_should_error {
465+
Err(ActivateError::BadActivate)
466+
} else {
467+
Ok(())
468+
}
462469
}
463470

464471
fn is_activated(&self) -> bool {
@@ -831,6 +838,63 @@ pub(crate) mod tests {
831838
assert_eq!(read_le_u32(&buf[..]), 1);
832839
}
833840

841+
#[test]
842+
fn test_bus_device_activate_failure() {
843+
let m = single_region_mem(0x1000);
844+
let device = DummyDevice {
845+
activate_should_error: true,
846+
..DummyDevice::new()
847+
};
848+
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(device)), false);
849+
850+
set_device_status(&mut d, device_status::ACKNOWLEDGE);
851+
set_device_status(&mut d, device_status::ACKNOWLEDGE | device_status::DRIVER);
852+
set_device_status(
853+
&mut d,
854+
device_status::ACKNOWLEDGE | device_status::DRIVER | device_status::FEATURES_OK,
855+
);
856+
857+
let mut buf = [0; 4];
858+
let queue_len = d.locked_device().queues().len();
859+
for q in 0..queue_len {
860+
d.queue_select = q.try_into().unwrap();
861+
write_le_u32(&mut buf[..], 16);
862+
d.bus_write(0x38, &buf[..]);
863+
write_le_u32(&mut buf[..], 1);
864+
d.bus_write(0x44, &buf[..]);
865+
}
866+
assert!(d.are_queues_valid());
867+
assert_eq!(
868+
d.locked_device().interrupt_status().load(Ordering::SeqCst),
869+
0
870+
);
871+
872+
set_device_status(
873+
&mut d,
874+
device_status::ACKNOWLEDGE
875+
| device_status::DRIVER
876+
| device_status::FEATURES_OK
877+
| device_status::DRIVER_OK,
878+
);
879+
880+
// Failure in activate results in `DEVICE_NEEDS_RESET` status being set
881+
assert_ne!(d.device_status & DEVICE_NEEDS_RESET, 0);
882+
// We injected an interrupt of type "configuration change"
883+
assert_eq!(
884+
d.locked_device().interrupt_status().load(Ordering::SeqCst),
885+
VIRTIO_MMIO_INT_CONFIG
886+
);
887+
// We actually wrote to the eventfd
888+
assert_eq!(
889+
d.locked_device()
890+
.interrupt_trigger()
891+
.irq_evt
892+
.read()
893+
.unwrap(),
894+
1
895+
);
896+
}
897+
834898
fn activate_device(d: &mut MmioTransport) {
835899
set_device_status(d, device_status::ACKNOWLEDGE);
836900
set_device_status(d, device_status::ACKNOWLEDGE | device_status::DRIVER);

0 commit comments

Comments
 (0)