Skip to content

Commit 1cce146

Browse files
committed
refactor: use VirtioInterrupt in VirtIO devices
VirtIO devices assume they're operating under an MMIO transport and as a consequence they use IrqTrigger as interrupts. Switch that to using VirtioInterrupt for all VirtIO device objects. Only assume a VirtioInterrupt is an IrqTrigger in MMIO specific code. Signed-off-by: Babis Chalios <bchalios@amazon.es>
1 parent b98365a commit 1cce146

29 files changed

+426
-309
lines changed

resources/seccomp/aarch64-unknown-linux-musl.json

+4
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,10 @@
10171017
{
10181018
"syscall": "restart_syscall",
10191019
"comment": "automatically issued by the kernel when specific timing-related syscalls (e.g. nanosleep) get interrupted by SIGSTOP"
1020+
},
1021+
{
1022+
"syscall": "dup",
1023+
"comment": "Used to get a copy of the EventFd that is backing a VirtioInterrupt object"
10201024
}
10211025
]
10221026
}

resources/seccomp/x86_64-unknown-linux-musl.json

+4
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,10 @@
11491149
{
11501150
"syscall": "restart_syscall",
11511151
"comment": "automatically issued by the kernel when specific timing-related syscalls (e.g. nanosleep) get interrupted by SIGSTOP"
1152+
},
1153+
{
1154+
"syscall": "dup",
1155+
"comment": "Used to get a copy of the EventFd that is backing a VirtioInterrupt object"
11521156
}
11531157
]
11541158
}

src/vmm/src/device_manager/mmio.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ impl MMIODeviceManager {
505505
.unwrap();
506506
if vsock.is_activated() {
507507
info!("kick vsock {id}.");
508-
vsock.signal_used_queue().unwrap();
508+
vsock.signal_used_queue(0).unwrap();
509509
}
510510
}
511511
TYPE_RNG => {
@@ -525,6 +525,7 @@ impl MMIODeviceManager {
525525
#[cfg(test)]
526526
mod tests {
527527

528+
use std::ops::Deref;
528529
use std::sync::Arc;
529530

530531
use vmm_sys_util::eventfd::EventFd;
@@ -534,6 +535,7 @@ mod tests {
534535
use crate::devices::virtio::ActivateError;
535536
use crate::devices::virtio::device::VirtioDevice;
536537
use crate::devices::virtio::queue::Queue;
538+
use crate::devices::virtio::transport::VirtioInterrupt;
537539
use crate::devices::virtio::transport::mmio::IrqTrigger;
538540
use crate::test_utils::multi_region_mem_raw;
539541
use crate::vstate::kvm::Kvm;
@@ -620,11 +622,8 @@ mod tests {
620622
&self.queue_evts
621623
}
622624

623-
fn interrupt_trigger(&self) -> Arc<IrqTrigger> {
624-
self.interrupt_trigger
625-
.as_ref()
626-
.expect("Device is not activated")
627-
.clone()
625+
fn interrupt_trigger(&self) -> &dyn VirtioInterrupt {
626+
self.interrupt_trigger.as_ref().unwrap().deref()
628627
}
629628

630629
fn ack_features_by_page(&mut self, page: u32, value: u32) {
@@ -645,7 +644,7 @@ mod tests {
645644
fn activate(
646645
&mut self,
647646
_: GuestMemoryMmap,
648-
_: Arc<IrqTrigger>,
647+
_: Arc<dyn VirtioInterrupt>,
649648
) -> Result<(), ActivateError> {
650649
Ok(())
651650
}

src/vmm/src/devices/virtio/balloon/device.rs

+34-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::ops::Deref;
45
use std::sync::Arc;
56
use std::time::Duration;
67

@@ -24,8 +25,9 @@ use super::{
2425
VIRTIO_BALLOON_S_SWAP_OUT,
2526
};
2627
use crate::devices::virtio::balloon::BalloonError;
28+
use crate::devices::virtio::device::ActiveState;
2729
use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1;
28-
use crate::devices::virtio::transport::mmio::{IrqTrigger, IrqType};
30+
use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType};
2931
use crate::logger::IncMetric;
3032
use crate::utils::u64_to_usize;
3133
use crate::vstate::memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap};
@@ -258,7 +260,7 @@ impl Balloon {
258260

259261
pub(crate) fn process_inflate(&mut self) -> Result<(), BalloonError> {
260262
// This is safe since we checked in the event handler that the device is activated.
261-
let (mem, _) = self.device_state.active_state().unwrap();
263+
let mem = &self.device_state.active_state().unwrap().mem;
262264
METRICS.inflate_count.inc();
263265

264266
let queue = &mut self.queues[INFLATE_INDEX];
@@ -339,7 +341,7 @@ impl Balloon {
339341
}
340342

341343
if needs_interrupt {
342-
self.signal_used_queue()?;
344+
self.signal_used_queue(INFLATE_INDEX)?;
343345
}
344346

345347
Ok(())
@@ -357,15 +359,15 @@ impl Balloon {
357359
}
358360

359361
if needs_interrupt {
360-
self.signal_used_queue()
362+
self.signal_used_queue(DEFLATE_INDEX)
361363
} else {
362364
Ok(())
363365
}
364366
}
365367

366368
pub(crate) fn process_stats_queue(&mut self) -> Result<(), BalloonError> {
367369
// This is safe since we checked in the event handler that the device is activated.
368-
let (mem, _) = self.device_state.active_state().unwrap();
370+
let mem = &self.device_state.active_state().unwrap().mem;
369371
METRICS.stats_updates_count.inc();
370372

371373
while let Some(head) = self.queues[STATS_INDEX].pop() {
@@ -401,9 +403,12 @@ impl Balloon {
401403
Ok(())
402404
}
403405

404-
pub(crate) fn signal_used_queue(&self) -> Result<(), BalloonError> {
406+
pub(crate) fn signal_used_queue(&self, qidx: usize) -> Result<(), BalloonError> {
405407
self.interrupt_trigger()
406-
.trigger_irq(IrqType::Vring)
408+
.trigger(VirtioInterruptType::Queue(
409+
qidx.try_into()
410+
.unwrap_or_else(|_| panic!("balloon: invalid queue id: {qidx}")),
411+
))
407412
.map_err(|err| {
408413
METRICS.event_fails.inc();
409414
BalloonError::InterruptError(err)
@@ -428,7 +433,7 @@ impl Balloon {
428433
self.queues[STATS_INDEX]
429434
.add_used(index, 0)
430435
.map_err(BalloonError::Queue)?;
431-
self.signal_used_queue()
436+
self.signal_used_queue(STATS_INDEX)
432437
} else {
433438
error!("Failed to update balloon stats, missing descriptor.");
434439
Ok(())
@@ -440,7 +445,7 @@ impl Balloon {
440445
if self.is_activated() {
441446
self.config_space.num_pages = mib_to_pages(amount_mib)?;
442447
self.interrupt_trigger()
443-
.trigger_irq(IrqType::Config)
448+
.trigger(VirtioInterruptType::Config)
444449
.map_err(BalloonError::InterruptError)
445450
} else {
446451
Err(BalloonError::DeviceNotActive)
@@ -551,11 +556,12 @@ impl VirtioDevice for Balloon {
551556
&self.queue_evts
552557
}
553558

554-
fn interrupt_trigger(&self) -> Arc<IrqTrigger> {
559+
fn interrupt_trigger(&self) -> &dyn VirtioInterrupt {
555560
self.device_state
556561
.active_state()
557562
.expect("Device is not activated")
558-
.1
563+
.interrupt
564+
.deref()
559565
}
560566

561567
fn read_config(&self, offset: u64, data: &mut [u8]) {
@@ -585,14 +591,14 @@ impl VirtioDevice for Balloon {
585591
fn activate(
586592
&mut self,
587593
mem: GuestMemoryMmap,
588-
interrupt: Arc<IrqTrigger>,
594+
interrupt: Arc<dyn VirtioInterrupt>,
589595
) -> Result<(), ActivateError> {
590596
for q in self.queues.iter_mut() {
591597
q.initialize(&mem)
592598
.map_err(ActivateError::QueueMemoryError)?;
593599
}
594600

595-
self.device_state = DeviceState::Activated((mem, interrupt));
601+
self.device_state = DeviceState::Activated(ActiveState { mem, interrupt });
596602
if self.activate_evt.write(1).is_err() {
597603
METRICS.activate_fails.inc();
598604
self.device_state = DeviceState::Inactive;
@@ -621,7 +627,7 @@ pub(crate) mod tests {
621627
check_request_completion, invoke_handler_for_queue_event, set_request,
622628
};
623629
use crate::devices::virtio::queue::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
624-
use crate::devices::virtio::test_utils::{VirtQueue, default_mem};
630+
use crate::devices::virtio::test_utils::{VirtQueue, default_interrupt, default_mem};
625631
use crate::test_utils::single_region_mem;
626632
use crate::vstate::memory::GuestAddress;
627633

@@ -798,11 +804,10 @@ pub(crate) mod tests {
798804
fn test_invalid_request() {
799805
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
800806
let mem = default_mem();
801-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
802807
// Only initialize the inflate queue to demonstrate invalid request handling.
803808
let infq = VirtQueue::new(GuestAddress(0), &mem, 16);
804809
balloon.set_queue(INFLATE_INDEX, infq.create_queue());
805-
balloon.activate(mem.clone(), interrupt).unwrap();
810+
balloon.activate(mem.clone(), default_interrupt()).unwrap();
806811

807812
// Fill the second page with non-zero bytes.
808813
for i in 0..0x1000 {
@@ -858,10 +863,9 @@ pub(crate) mod tests {
858863
fn test_inflate() {
859864
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
860865
let mem = default_mem();
861-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
862866
let infq = VirtQueue::new(GuestAddress(0), &mem, 16);
863867
balloon.set_queue(INFLATE_INDEX, infq.create_queue());
864-
balloon.activate(mem.clone(), interrupt).unwrap();
868+
balloon.activate(mem.clone(), default_interrupt()).unwrap();
865869

866870
// Fill the third page with non-zero bytes.
867871
for i in 0..0x1000 {
@@ -929,10 +933,9 @@ pub(crate) mod tests {
929933
fn test_deflate() {
930934
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
931935
let mem = default_mem();
932-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
933936
let defq = VirtQueue::new(GuestAddress(0), &mem, 16);
934937
balloon.set_queue(DEFLATE_INDEX, defq.create_queue());
935-
balloon.activate(mem.clone(), interrupt).unwrap();
938+
balloon.activate(mem.clone(), default_interrupt()).unwrap();
936939

937940
let page_addr = 0x10;
938941

@@ -978,10 +981,9 @@ pub(crate) mod tests {
978981
fn test_stats() {
979982
let mut balloon = Balloon::new(0, true, 1, false).unwrap();
980983
let mem = default_mem();
981-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
982984
let statsq = VirtQueue::new(GuestAddress(0), &mem, 16);
983985
balloon.set_queue(STATS_INDEX, statsq.create_queue());
984-
balloon.activate(mem.clone(), interrupt).unwrap();
986+
balloon.activate(mem.clone(), default_interrupt()).unwrap();
985987

986988
let page_addr = 0x100;
987989

@@ -1057,7 +1059,9 @@ pub(crate) mod tests {
10571059
assert!(balloon.stats_desc_index.is_some());
10581060
balloon.process_stats_timer_event().unwrap();
10591061
assert!(balloon.stats_desc_index.is_none());
1060-
assert!(balloon.interrupt_trigger().has_pending_irq(IrqType::Vring));
1062+
assert!(balloon.interrupt_trigger().has_pending_interrupt(
1063+
VirtioInterruptType::Queue(STATS_INDEX.try_into().unwrap())
1064+
));
10611065
});
10621066
}
10631067
}
@@ -1066,23 +1070,21 @@ pub(crate) mod tests {
10661070
fn test_process_balloon_queues() {
10671071
let mut balloon = Balloon::new(0x10, true, 0, false).unwrap();
10681072
let mem = default_mem();
1069-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
10701073
let infq = VirtQueue::new(GuestAddress(0), &mem, 16);
10711074
let defq = VirtQueue::new(GuestAddress(0), &mem, 16);
10721075

10731076
balloon.set_queue(INFLATE_INDEX, infq.create_queue());
10741077
balloon.set_queue(DEFLATE_INDEX, defq.create_queue());
10751078

1076-
balloon.activate(mem, interrupt).unwrap();
1079+
balloon.activate(mem, default_interrupt()).unwrap();
10771080
balloon.process_virtio_queues()
10781081
}
10791082

10801083
#[test]
10811084
fn test_update_stats_interval() {
10821085
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
10831086
let mem = default_mem();
1084-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
1085-
balloon.activate(mem, interrupt).unwrap();
1087+
balloon.activate(mem, default_interrupt()).unwrap();
10861088
assert_eq!(
10871089
format!("{:?}", balloon.update_stats_polling_interval(1)),
10881090
"Err(StatisticsStateChange)"
@@ -1091,8 +1093,7 @@ pub(crate) mod tests {
10911093

10921094
let mut balloon = Balloon::new(0, true, 1, false).unwrap();
10931095
let mem = default_mem();
1094-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
1095-
balloon.activate(mem, interrupt).unwrap();
1096+
balloon.activate(mem, default_interrupt()).unwrap();
10961097
assert_eq!(
10971098
format!("{:?}", balloon.update_stats_polling_interval(0)),
10981099
"Err(StatisticsStateChange)"
@@ -1112,8 +1113,10 @@ pub(crate) mod tests {
11121113
fn test_num_pages() {
11131114
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
11141115
// Switch the state to active.
1115-
balloon.device_state =
1116-
DeviceState::Activated((single_region_mem(0x1), Arc::new(IrqTrigger::new().unwrap())));
1116+
balloon.device_state = DeviceState::Activated(ActiveState {
1117+
mem: single_region_mem(0x1),
1118+
interrupt: default_interrupt(),
1119+
});
11171120

11181121
assert_eq!(balloon.num_pages(), 0);
11191122
assert_eq!(balloon.actual_pages(), 0);

src/vmm/src/devices/virtio/balloon/event_handler.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,15 @@ pub mod tests {
136136

137137
use super::*;
138138
use crate::devices::virtio::balloon::test_utils::set_request;
139-
use crate::devices::virtio::test_utils::{VirtQueue, default_mem};
140-
use crate::devices::virtio::transport::mmio::IrqTrigger;
139+
use crate::devices::virtio::test_utils::{VirtQueue, default_interrupt, default_mem};
141140
use crate::vstate::memory::GuestAddress;
142141

143142
#[test]
144143
fn test_event_handler() {
145144
let mut event_manager = EventManager::new().unwrap();
146145
let mut balloon = Balloon::new(0, true, 10, false).unwrap();
147146
let mem = default_mem();
148-
let interrupt = Arc::new(IrqTrigger::new().unwrap());
147+
let interrupt = default_interrupt();
149148
let infq = VirtQueue::new(GuestAddress(0), &mem, 16);
150149
balloon.set_queue(INFLATE_INDEX, infq.create_queue());
151150

src/vmm/src/devices/virtio/balloon/persist.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use timerfd::{SetTimeFlags, TimerState};
1212
use super::*;
1313
use crate::devices::virtio::TYPE_BALLOON;
1414
use crate::devices::virtio::balloon::device::{BalloonStats, ConfigSpace};
15-
use crate::devices::virtio::device::DeviceState;
15+
use crate::devices::virtio::device::{ActiveState, DeviceState};
1616
use crate::devices::virtio::persist::VirtioDeviceState;
1717
use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE;
18-
use crate::devices::virtio::transport::mmio::IrqTrigger;
18+
use crate::devices::virtio::transport::VirtioInterrupt;
1919
use crate::snapshot::Persist;
2020
use crate::vstate::memory::GuestMemoryMmap;
2121

@@ -96,7 +96,7 @@ pub struct BalloonConstructorArgs {
9696
/// Pointer to guest memory.
9797
pub mem: GuestMemoryMmap,
9898
/// Interrupt used from the device.
99-
pub interrupt: Arc<IrqTrigger>,
99+
pub interrupt: Arc<dyn VirtioInterrupt>,
100100
pub restored_from_file: bool,
101101
}
102102

@@ -155,8 +155,10 @@ impl Persist<'_> for Balloon {
155155
};
156156

157157
if state.virtio_state.activated {
158-
balloon.device_state =
159-
DeviceState::Activated((constructor_args.mem, constructor_args.interrupt));
158+
balloon.device_state = DeviceState::Activated(ActiveState {
159+
mem: constructor_args.mem,
160+
interrupt: constructor_args.interrupt,
161+
});
160162

161163
if balloon.stats_enabled() {
162164
// Restore the stats descriptor.

src/vmm/src/devices/virtio/balloon/test_utils.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33

44
#![doc(hidden)]
55

6+
#[cfg(test)]
7+
use crate::devices::virtio::device::VirtioDevice;
68
use crate::devices::virtio::test_utils::VirtQueue;
79
#[cfg(test)]
810
use crate::devices::virtio::{balloon::BALLOON_NUM_QUEUES, balloon::Balloon};
911

1012
#[cfg(test)]
1113
pub fn invoke_handler_for_queue_event(b: &mut Balloon, queue_index: usize) {
1214
use crate::devices::virtio::balloon::{DEFLATE_INDEX, INFLATE_INDEX, STATS_INDEX};
13-
use crate::devices::virtio::transport::mmio::IrqType;
15+
use crate::devices::virtio::transport::VirtioInterruptType;
1416

1517
assert!(queue_index < BALLOON_NUM_QUEUES);
1618
// Trigger the queue event.
@@ -23,8 +25,11 @@ pub fn invoke_handler_for_queue_event(b: &mut Balloon, queue_index: usize) {
2325
_ => unreachable!(),
2426
};
2527
// Validate the queue operation finished successfully.
26-
let (_, interrupt) = b.device_state.active_state().unwrap();
27-
assert!(interrupt.has_pending_irq(IrqType::Vring));
28+
let interrupt = b.interrupt_trigger();
29+
assert!(
30+
interrupt
31+
.has_pending_interrupt(VirtioInterruptType::Queue(queue_index.try_into().unwrap()))
32+
);
2833
}
2934

3035
pub fn set_request(queue: &VirtQueue, idx: u16, addr: u64, len: u32, flags: u16) {

0 commit comments

Comments
 (0)