diff --git a/vm-virtio/src/vhost_user/blk.rs b/vm-virtio/src/vhost_user/blk.rs index 79a46c9b5..293292b32 100644 --- a/vm-virtio/src/vhost_user/blk.rs +++ b/vm-virtio/src/vhost_user/blk.rs @@ -260,6 +260,7 @@ impl VirtioDevice for Blk { mem.load().as_ref(), queues, queue_evts, + &interrupt_cb, self.acked_features, ) .map_err(ActivateError::VhostUserBlkSetup)?; diff --git a/vm-virtio/src/vhost_user/fs.rs b/vm-virtio/src/vhost_user/fs.rs index 1cde98e85..770a1a238 100644 --- a/vm-virtio/src/vhost_user/fs.rs +++ b/vm-virtio/src/vhost_user/fs.rs @@ -382,6 +382,7 @@ impl VirtioDevice for Fs { mem.load().as_ref(), queues, queue_evts, + &interrupt_cb, self.acked_features, ) .map_err(ActivateError::VhostUserSetup)?; diff --git a/vm-virtio/src/vhost_user/handler.rs b/vm-virtio/src/vhost_user/handler.rs index 22a722aed..b5d5fa311 100644 --- a/vm-virtio/src/vhost_user/handler.rs +++ b/vm-virtio/src/vhost_user/handler.rs @@ -31,7 +31,7 @@ pub struct VhostUserEpollConfig { pub interrupt_cb: Arc, pub kill_evt: EventFd, pub pause_evt: EventFd, - pub vu_interrupt_list: Vec<(EventFd, Queue)>, + pub vu_interrupt_list: Vec<(Option, Queue)>, pub slave_req_handler: Option>, } @@ -64,14 +64,16 @@ impl VhostUserEpollHandler { for (index, vhost_user_interrupt) in self.vu_epoll_cfg.vu_interrupt_list.iter().enumerate() { - // Add events - epoll::ctl( - epoll_fd, - epoll::ControlOptions::EPOLL_CTL_ADD, - vhost_user_interrupt.0.as_raw_fd(), - epoll::Event::new(epoll::Events::EPOLLIN, index as u64), - ) - .map_err(Error::EpollCtl)?; + if let Some(eventfd) = &vhost_user_interrupt.0 { + // Add events + epoll::ctl( + epoll_fd, + epoll::ControlOptions::EPOLL_CTL_ADD, + eventfd.as_raw_fd(), + epoll::Event::new(epoll::Events::EPOLLIN, index as u64), + ) + .map_err(Error::EpollCtl)?; + } } let kill_evt_index = self.vu_epoll_cfg.vu_interrupt_list.len(); @@ -136,15 +138,14 @@ impl VhostUserEpollHandler { match ev_type { x if x < kill_evt_index => { - self.vu_epoll_cfg.vu_interrupt_list[x] - .0 - .read() - .map_err(Error::FailedReadingQueue)?; - if let Err(e) = - self.signal_used_queue(&self.vu_epoll_cfg.vu_interrupt_list[x].1) - { - error!("Failed to signal used queue: {:?}", e); - break 'poll; + if let Some(eventfd) = &self.vu_epoll_cfg.vu_interrupt_list[x].0 { + eventfd.read().map_err(Error::FailedReadingQueue)?; + if let Err(e) = + self.signal_used_queue(&self.vu_epoll_cfg.vu_interrupt_list[x].1) + { + error!("Failed to signal used queue: {:?}", e); + break 'poll; + } } } x if kill_evt_index == x => { diff --git a/vm-virtio/src/vhost_user/net.rs b/vm-virtio/src/vhost_user/net.rs index 7e2c26f3b..46d5881e6 100644 --- a/vm-virtio/src/vhost_user/net.rs +++ b/vm-virtio/src/vhost_user/net.rs @@ -302,13 +302,14 @@ impl VirtioDevice for Net { mem.load().as_ref(), queues, queue_evts, + &interrupt_cb, self.acked_features & self.backend_features, ) .map_err(ActivateError::VhostUserNetSetup)?; let mut epoll_thread = Vec::new(); for _ in 0..vu_interrupt_list.len() / 2 { - let mut interrupt_list_sub: Vec<(EventFd, Queue)> = Vec::with_capacity(2); + let mut interrupt_list_sub: Vec<(Option, Queue)> = Vec::with_capacity(2); interrupt_list_sub.push(vu_interrupt_list.remove(0)); interrupt_list_sub.push(vu_interrupt_list.remove(0)); diff --git a/vm-virtio/src/vhost_user/vu_common_ctrl.rs b/vm-virtio/src/vhost_user/vu_common_ctrl.rs index 122ff1454..89318a2cf 100644 --- a/vm-virtio/src/vhost_user/vu_common_ctrl.rs +++ b/vm-virtio/src/vhost_user/vu_common_ctrl.rs @@ -5,9 +5,11 @@ use libc; use libc::EFD_NONBLOCK; use std::convert::TryInto; use std::os::unix::io::AsRawFd; +use std::sync::Arc; use std::vec::Vec; use crate::queue::Descriptor; +use crate::{VirtioInterrupt, VirtioInterruptType}; use vm_device::get_host_address_range; use vm_memory::{Address, Error as MmapError, GuestMemory, GuestMemoryMmap, GuestMemoryRegion}; @@ -30,7 +32,8 @@ pub fn setup_vhost_user_vring( mem: &GuestMemoryMmap, queues: Vec, queue_evts: Vec, -) -> Result> { + virtio_interrupt: &Arc, +) -> Result, Queue)>> { let mut regions: Vec = Vec::new(); mem.with_regions_mut(|_, region| { let (mmap_handle, mmap_offset) = match region.file_offset() { @@ -89,10 +92,17 @@ pub fn setup_vhost_user_vring( vu.set_vring_base(queue_index, 0u16) .map_err(Error::VhostUserSetVringBase)?; - let vhost_user_interrupt = EventFd::new(EFD_NONBLOCK).map_err(Error::VhostIrqCreate)?; - vu.set_vring_call(queue_index, &vhost_user_interrupt) - .map_err(Error::VhostUserSetVringCall)?; - vu_interrupt_list.push((vhost_user_interrupt, queue)); + if let Some(eventfd) = virtio_interrupt.notifier(&VirtioInterruptType::Queue, Some(&queue)) + { + vu.set_vring_call(queue_index, &eventfd) + .map_err(Error::VhostUserSetVringCall)?; + vu_interrupt_list.push((None, queue)); + } else { + let eventfd = EventFd::new(EFD_NONBLOCK).map_err(Error::VhostIrqCreate)?; + vu.set_vring_call(queue_index, &eventfd) + .map_err(Error::VhostUserSetVringCall)?; + vu_interrupt_list.push((Some(eventfd), queue)); + } vu.set_vring_kick(queue_index, &queue_evts[queue_index]) .map_err(Error::VhostUserSetVringKick)?; @@ -109,13 +119,14 @@ pub fn setup_vhost_user( mem: &GuestMemoryMmap, queues: Vec, queue_evts: Vec, + virtio_interrupt: &Arc, acked_features: u64, -) -> Result> { +) -> Result, Queue)>> { // Set features based on the acked features from the guest driver. vu.set_features(acked_features) .map_err(Error::VhostUserSetFeatures)?; - setup_vhost_user_vring(vu, mem, queues, queue_evts) + setup_vhost_user_vring(vu, mem, queues, queue_evts, virtio_interrupt) } pub fn reset_vhost_user(vu: &mut Master, num_queues: usize) -> Result<()> {