mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 19:32:20 +00:00
virtio-devices: vhost_user: Add pause/resume support
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
d4b8c8308c
commit
382b37f8d1
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user