diff --git a/virtio-devices/src/device.rs b/virtio-devices/src/device.rs index f0673f561..96a40a4da 100644 --- a/virtio-devices/src/device.rs +++ b/virtio-devices/src/device.rs @@ -13,6 +13,7 @@ use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use std::sync::{Arc, Barrier}; use std::thread; +use anyhow::anyhow; use libc::EFD_NONBLOCK; use log::{error, info, warn}; use virtio_queue::Queue; @@ -215,6 +216,7 @@ pub struct VirtioCommon { pub paused_sync: Option>, pub epoll_threads: Option>>, pub queue_sizes: Vec, + pub queue_evts: Vec, pub device_type: u32, pub min_queues: u16, pub access_platform: Option>, @@ -252,6 +254,21 @@ impl VirtioCommon { return Err(ActivateError::BadActivate); } + // Do not retain virtio-net queue eventfds here. Signaling them on + // resume would break its `driver_awake` workaround. + self.queue_evts = match VirtioDeviceType::from(self.device_type) { + VirtioDeviceType::Net => Vec::new(), + _ => queues + .iter() + .map(|(_, _, queue_evt)| { + queue_evt.try_clone().map_err(|e| { + error!("failed cloning queue EventFd: {e}"); + ActivateError::BadActivate + }) + }) + .collect::, _>>()?, + }; + let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(|e| { error!("failed creating kill EventFd: {e}"); ActivateError::BadActivate @@ -272,6 +289,8 @@ impl VirtioCommon { } pub fn reset(&mut self) -> Option> { + self.queue_evts.clear(); + // We first must resume the virtio thread if it was paused. if self.pause_evt.take().is_some() { self.resume().ok()?; @@ -355,6 +374,16 @@ impl Pausable for VirtioCommon { } } + // Signal each activated queue eventfd so workers process restored queues + // that may already contain pending requests. + for queue_evt in &self.queue_evts { + queue_evt.write(1).map_err(|e| { + MigratableError::Resume(anyhow!( + "Could not notify restored virtio worker on resume: {e}" + )) + })?; + } + Ok(()) } }