virtio-devices: vhost_user: Reconnection for slave request handler

Add the support for reconnecting the backend request handler after a
disconnection/crash happened.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-06-09 17:27:14 +02:00
parent acec7e34fc
commit 1a5c6631a5
5 changed files with 39 additions and 29 deletions

View File

@ -23,7 +23,7 @@ use std::vec::Vec;
use vhost::vhost_user::message::VhostUserConfigFlags;
use vhost::vhost_user::message::VHOST_USER_CONFIG_OFFSET;
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use vhost::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler};
use vhost::VhostBackend;
use virtio_bindings::bindings::virtio_blk::{
VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH,
@ -215,6 +215,8 @@ impl VirtioDevice for Blk {
self.guest_memory = Some(mem.clone());
let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None;
// The backend acknowledged features must contain the protocol feature
// bit in case it was initially set but lost through the features
// negotiation with the guest.
@ -228,6 +230,7 @@ impl VirtioDevice for Blk {
queue_evts.iter().map(|q| q.try_clone().unwrap()).collect(),
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
)
.map_err(ActivateError::VhostUserBlkSetup)?;

View File

@ -415,22 +415,6 @@ impl VirtioDevice for Fs {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
self.guest_memory = Some(mem.clone());
// The backend acknowledged features must contain the protocol feature
// bit in case it was initially set but lost through the features
// negotiation with the guest.
let backend_acked_features = self.common.acked_features
| (self.common.avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits());
setup_vhost_user(
&mut self.vu.lock().unwrap(),
&mem.memory(),
queues.clone(),
queue_evts.iter().map(|q| q.try_clone().unwrap()).collect(),
&interrupt_cb,
backend_acked_features,
)
.map_err(ActivateError::VhostUserFsSetup)?;
// Initialize slave communication.
let slave_req_handler = if self.slave_req_support {
if let Some(cache) = self.cache.as_ref() {
@ -446,13 +430,6 @@ impl VirtioDevice for Fs {
ActivateError::VhostUserFsSetup(Error::MasterReqHandlerCreation(e))
})?;
req_handler.set_reply_ack_flag(true);
self.vu
.lock()
.unwrap()
.set_slave_request_fd(req_handler.get_tx_raw_fd())
.map_err(|e| {
ActivateError::VhostUserFsSetup(Error::VhostUserSetSlaveRequestFd(e))
})?;
Some(req_handler)
} else {
None
@ -461,6 +438,23 @@ impl VirtioDevice for Fs {
None
};
// The backend acknowledged features must contain the protocol feature
// bit in case it was initially set but lost through the features
// negotiation with the guest.
let backend_acked_features = self.common.acked_features
| (self.common.avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits());
setup_vhost_user(
&mut self.vu.lock().unwrap(),
&mem.memory(),
queues.clone(),
queue_evts.iter().map(|q| q.try_clone().unwrap()).collect(),
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
)
.map_err(ActivateError::VhostUserFsSetup)?;
// Run a dedicated thread for handling potential reconnections with
// the backend as well as requests initiated by the backend.
let (kill_evt, pause_evt) = self.common.dup_eventfds();

View File

@ -197,6 +197,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
&self.virtio_interrupt,
self.acked_features,
self.acked_protocol_features,
&self.slave_req_handler,
)
.map_err(|e| {
EpollHelperError::IoError(std::io::Error::new(

View File

@ -23,7 +23,7 @@ use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use std::vec::Vec;
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use vhost::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler};
use virtio_bindings::bindings::virtio_net::{
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN,
VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO,
@ -283,6 +283,8 @@ impl VirtioDevice for Net {
})?;
}
let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None;
// The backend acknowledged features must contain the protocol feature
// bit in case it was initially set but lost through the features
// negotiation with the guest. Additionally, it must not contain
@ -297,6 +299,7 @@ impl VirtioDevice for Net {
queue_evts.iter().map(|q| q.try_clone().unwrap()).collect(),
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
)
.map_err(ActivateError::VhostUserNetSetup)?;

View File

@ -13,7 +13,7 @@ use std::thread::sleep;
use std::time::{Duration, Instant};
use std::vec::Vec;
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use vhost::vhost_user::{Master, VhostUserMaster};
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler};
use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData};
use vm_memory::{Address, Error as MmapError, GuestMemory, GuestMemoryRegion};
use vmm_sys_util::eventfd::EventFd;
@ -100,13 +100,14 @@ pub fn negotiate_features_vhost_user(
Ok((acked_features, acked_protocol_features))
}
pub fn setup_vhost_user(
pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
vu: &mut Master,
mem: &GuestMemoryMmap,
queues: Vec<Queue>,
queue_evts: Vec<EventFd>,
virtio_interrupt: &Arc<dyn VirtioInterrupt>,
acked_features: u64,
slave_req_handler: &Option<MasterReqHandler<S>>,
) -> Result<()> {
vu.set_features(acked_features)
.map_err(Error::VhostUserSetFeatures)?;
@ -164,7 +165,12 @@ pub fn setup_vhost_user(
.map_err(Error::VhostUserSetVringEnable)?;
}
Ok(())
if let Some(slave_req_handler) = slave_req_handler {
vu.set_slave_request_fd(slave_req_handler.get_tx_raw_fd())
.map_err(Error::VhostUserSetSlaveRequestFd)
} else {
Ok(())
}
}
pub fn reset_vhost_user(vu: &mut Master, num_queues: usize) -> Result<()> {
@ -178,7 +184,8 @@ pub fn reset_vhost_user(vu: &mut Master, num_queues: usize) -> Result<()> {
vu.reset_owner().map_err(Error::VhostUserResetOwner)
}
pub fn reinitialize_vhost_user(
#[allow(clippy::too_many_arguments)]
pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>(
vu: &mut Master,
mem: &GuestMemoryMmap,
queues: Vec<Queue>,
@ -186,6 +193,7 @@ pub fn reinitialize_vhost_user(
virtio_interrupt: &Arc<dyn VirtioInterrupt>,
acked_features: u64,
acked_protocol_features: u64,
slave_req_handler: &Option<MasterReqHandler<S>>,
) -> Result<()> {
vu.set_owner().map_err(Error::VhostUserSetOwner)?;
vu.get_features().map_err(Error::VhostUserGetFeatures)?;
@ -206,6 +214,7 @@ pub fn reinitialize_vhost_user(
queue_evts,
virtio_interrupt,
acked_features,
slave_req_handler,
)
}