virtio-devices: vhost_user: Add pause/resume support

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-07-26 22:06:54 +02:00 committed by Bo Chen
parent d4b8c8308c
commit 382b37f8d1
5 changed files with 99 additions and 14 deletions

View File

@ -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<thread::JoinHandle<()>>,
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<EventFd>,
) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
self.guest_memory = Some(mem.clone());
let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = 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))
})
}
}

View File

@ -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<thread::JoinHandle<()>>,
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))
})
}
}

View File

@ -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.

View File

@ -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<thread::JoinHandle<()>>,
epoll_thread: Option<thread::JoinHandle<()>>,
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<EventFd>,
) -> 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))
})
}
}

View File

@ -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(())
}
}