diff --git a/virtio-devices/src/vhost_user/blk.rs b/virtio-devices/src/vhost_user/blk.rs index c4d702711..29ab67cf3 100644 --- a/virtio-devices/src/vhost_user/blk.rs +++ b/virtio-devices/src/vhost_user/blk.rs @@ -9,6 +9,7 @@ use super::{Error, Result, DEFAULT_VIRTIO_FEATURES}; use crate::vhost_user::{Inflight, VhostUserEpollHandler}; use crate::VirtioInterrupt; use crate::{GuestMemoryMmap, GuestRegionMmap}; +use anyhow::anyhow; use block_util::VirtioBlockConfig; use std::mem; use std::ops::Deref; @@ -45,6 +46,7 @@ pub struct Blk { acked_protocol_features: u64, socket_path: String, epoll_thread: Option>, + vu_num_queues: usize, } impl Blk { @@ -139,6 +141,7 @@ impl Blk { acked_protocol_features, socket_path: vu_cfg.socket, epoll_thread: None, + vu_num_queues: num_queues, }) } } @@ -209,7 +212,6 @@ impl VirtioDevice for Blk { queue_evts: Vec, ) -> ActivateResult { self.common.activate(&queues, &queue_evts, &interrupt_cb)?; - self.guest_memory = Some(mem.clone()); let slave_req_handler: Option> = None; @@ -337,6 +339,14 @@ impl VirtioDevice for Blk { impl Pausable for Blk { fn pause(&mut self) -> result::Result<(), MigratableError> { + self.vu + .lock() + .unwrap() + .pause_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Pause(anyhow!("Error pausing vhost-user-blk backend: {:?}", e)) + })?; + self.common.pause() } @@ -346,7 +356,14 @@ impl Pausable for Blk { if let Some(epoll_thread) = &self.epoll_thread { epoll_thread.thread().unpark(); } - Ok(()) + + self.vu + .lock() + .unwrap() + .resume_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Resume(anyhow!("Error resuming vhost-user-blk backend: {:?}", e)) + }) } } diff --git a/virtio-devices/src/vhost_user/fs.rs b/virtio-devices/src/vhost_user/fs.rs index 6832b6857..79789ce06 100644 --- a/virtio-devices/src/vhost_user/fs.rs +++ b/virtio-devices/src/vhost_user/fs.rs @@ -10,6 +10,7 @@ use crate::{ VirtioDeviceType, VirtioInterrupt, VirtioSharedMemoryList, }; use crate::{GuestMemoryMmap, GuestRegionMmap, MmapRegion}; +use anyhow::anyhow; use libc::{self, c_void, off64_t, pread64, pwrite64}; use seccomp::{SeccompAction, SeccompFilter}; use std::io; @@ -294,6 +295,7 @@ pub struct Fs { acked_protocol_features: u64, socket_path: String, epoll_thread: Option>, + vu_num_queues: usize, } impl Fs { @@ -380,6 +382,7 @@ impl Fs { acked_protocol_features, socket_path: path.to_string(), epoll_thread: None, + vu_num_queues: num_queues, }) } } @@ -607,6 +610,14 @@ impl VirtioDevice for Fs { impl Pausable for Fs { fn pause(&mut self) -> result::Result<(), MigratableError> { + self.vu + .lock() + .unwrap() + .pause_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Pause(anyhow!("Error pausing vhost-user-fs backend: {:?}", e)) + })?; + self.common.pause() } @@ -616,7 +627,14 @@ impl Pausable for Fs { if let Some(epoll_thread) = &self.epoll_thread { epoll_thread.thread().unpark(); } - Ok(()) + + self.vu + .lock() + .unwrap() + .resume_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Resume(anyhow!("Error resuming vhost-user-fs backend: {:?}", e)) + }) } } diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs index 5d7dbd67a..4a8c625cf 100644 --- a/virtio-devices/src/vhost_user/mod.rs +++ b/virtio-devices/src/vhost_user/mod.rs @@ -63,6 +63,8 @@ pub enum Error { VhostUserGetQueueMaxNum(VhostError), /// Get protocol features failed. VhostUserGetProtocolFeatures(VhostError), + /// Get vring base failed. + VhostUserGetVringBase(VhostError), /// Vhost-user Backend not support vhost-user protocol. VhostUserProtocolNotSupport, /// Set owner failed. diff --git a/virtio-devices/src/vhost_user/net.rs b/virtio-devices/src/vhost_user/net.rs index 6d31309c5..8524bf6f7 100644 --- a/virtio-devices/src/vhost_user/net.rs +++ b/virtio-devices/src/vhost_user/net.rs @@ -10,6 +10,7 @@ use crate::{ VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1, }; use crate::{GuestMemoryMmap, GuestRegionMmap}; +use anyhow::anyhow; use net_util::{build_net_config_space, CtrlQueue, MacAddr, VirtioNetConfig}; use seccomp::{SeccompAction, SeccompFilter}; use std::ops::Deref; @@ -100,6 +101,7 @@ pub struct Net { ctrl_queue_epoll_thread: Option>, epoll_thread: Option>, seccomp_action: SeccompAction, + vu_num_queues: usize, } impl Net { @@ -161,6 +163,7 @@ impl Net { // If the control queue feature has been negotiated, let's increase // the number of queues. + let vu_num_queues = num_queues; if acked_features & (1 << VIRTIO_NET_F_CTRL_VQ) != 0 { num_queues += 1; } @@ -189,6 +192,7 @@ impl Net { ctrl_queue_epoll_thread: None, epoll_thread: None, seccomp_action, + vu_num_queues, }) } } @@ -232,7 +236,6 @@ impl VirtioDevice for Net { mut queue_evts: Vec, ) -> ActivateResult { self.common.activate(&queues, &queue_evts, &interrupt_cb)?; - self.guest_memory = Some(mem.clone()); let num_queues = queues.len(); @@ -409,21 +412,35 @@ impl VirtioDevice for Net { impl Pausable for Net { fn pause(&mut self) -> result::Result<(), MigratableError> { + self.vu + .lock() + .unwrap() + .pause_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Pause(anyhow!("Error pausing vhost-user-net backend: {:?}", e)) + })?; + self.common.pause() } fn resume(&mut self) -> result::Result<(), MigratableError> { self.common.resume()?; - if let Some(ctrl_queue_epoll_thread) = &self.ctrl_queue_epoll_thread { - ctrl_queue_epoll_thread.thread().unpark(); - } - if let Some(epoll_thread) = &self.epoll_thread { epoll_thread.thread().unpark(); } - Ok(()) + if let Some(ctrl_queue_epoll_thread) = &self.ctrl_queue_epoll_thread { + ctrl_queue_epoll_thread.thread().unpark(); + } + + self.vu + .lock() + .unwrap() + .resume_vhost_user(self.vu_num_queues) + .map_err(|e| { + MigratableError::Resume(anyhow!("Error resuming vhost-user-net backend: {:?}", e)) + }) } } diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs index cb62505e1..e6d284f62 100644 --- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs +++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs @@ -31,6 +31,7 @@ pub struct VhostUserConfig { #[derive(Clone)] pub struct VhostUserHandle { vu: Master, + ready: bool, } impl VhostUserHandle { @@ -197,7 +198,7 @@ impl VhostUserHandle { .set_vring_base( queue_index, queue - .avail_index_from_memory(mem) + .used_index_from_memory(mem) .map_err(Error::GetAvailableIndex)?, ) .map_err(Error::VhostUserSetVringBase)?; @@ -222,10 +223,12 @@ impl VhostUserHandle { if let Some(slave_req_handler) = slave_req_handler { self.vu .set_slave_request_fd(&slave_req_handler.get_tx_raw_fd()) - .map_err(Error::VhostUserSetSlaveRequestFd) - } else { - Ok(()) + .map_err(Error::VhostUserSetSlaveRequestFd)?; } + + self.ready = true; + + Ok(()) } pub fn reset_vhost_user(&mut self, num_queues: usize) -> Result<()> { @@ -300,6 +303,7 @@ impl VhostUserHandle { Ok(VhostUserHandle { vu: Master::from_stream(stream, num_queues), + ready: false, }) } else { let now = Instant::now(); @@ -307,7 +311,12 @@ impl VhostUserHandle { // Retry connecting for a full minute let err = loop { let err = match Master::connect(socket_path, num_queues) { - Ok(m) => return Ok(VhostUserHandle { vu: m }), + Ok(m) => { + return Ok(VhostUserHandle { + vu: m, + ready: false, + }) + } Err(e) => e, }; sleep(Duration::from_millis(100)); @@ -328,4 +337,26 @@ impl VhostUserHandle { pub fn socket_handle(&mut self) -> &mut Master { &mut self.vu } + + pub fn pause_vhost_user(&mut self, num_queues: usize) -> Result<()> { + if self.ready { + for i in 0..num_queues { + self.vu + .set_vring_enable(i, false) + .map_err(Error::VhostUserSetVringEnable)?; + } + } + Ok(()) + } + + pub fn resume_vhost_user(&mut self, num_queues: usize) -> Result<()> { + if self.ready { + for i in 0..num_queues { + self.vu + .set_vring_enable(i, true) + .map_err(Error::VhostUserSetVringEnable)?; + } + } + Ok(()) + } }