virtio-devices: vhost_user: Support inflight I/O tracking

Vhost user INFLIGHT_SHMFD protocol feature supports inflight I/O
tracking, this commit implement the vhost-user device (master) support
of the feature. Till this commit, specific vhost-user devices (blk, fs,
or net) have not enable this feature.

Signed-off-by: Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
This commit is contained in:
Jiachen Zhang 2021-06-10 15:37:30 +08:00 committed by Sebastien Boeuf
parent f060ecd705
commit bfd4aa2fed
8 changed files with 67 additions and 4 deletions

2
Cargo.lock generated
View File

@ -1111,7 +1111,7 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vhost?branch=master#30ba3e7bbe9e0542cf480f44bc6845a8dbd2a6ba"
source = "git+https://github.com/rust-vmm/vhost?branch=master#a8ff939161d41fc2f449b80e461d013c1e19f666"
dependencies = [
"bitflags",
"libc",

2
fuzz/Cargo.lock generated
View File

@ -652,7 +652,7 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vhost?branch=master#e5b930b73a47cbdd79858e2e68bcb57123d1c1f3"
source = "git+https://github.com/rust-vmm/vhost?branch=master#a8ff939161d41fc2f449b80e461d013c1e19f666"
dependencies = [
"bitflags",
"libc",

View File

@ -959,6 +959,24 @@ impl<S: VhostUserBackend> VhostUserSlaveReqHandlerMut for VhostUserHandler<S> {
Ok(())
}
fn get_inflight_fd(
&mut self,
_: &vhost::vhost_user::message::VhostUserInflight,
) -> std::result::Result<
(vhost::vhost_user::message::VhostUserInflight, i32),
vhost::vhost_user::Error,
> {
std::unimplemented!()
}
fn set_inflight_fd(
&mut self,
_: &vhost::vhost_user::message::VhostUserInflight,
_: std::fs::File,
) -> std::result::Result<(), vhost::vhost_user::Error> {
std::unimplemented!()
}
}
impl<S: VhostUserBackend> Drop for VhostUserHandler<S> {

View File

@ -231,6 +231,7 @@ impl VirtioDevice for Blk {
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
None,
)
.map_err(ActivateError::VhostUserBlkSetup)?;
@ -251,6 +252,7 @@ impl VirtioDevice for Blk {
socket_path: self.socket_path.clone(),
server: false,
slave_req_handler: None,
inflight: None,
};
let paused = self.common.paused.clone();

View File

@ -452,6 +452,7 @@ impl VirtioDevice for Fs {
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
None,
)
.map_err(ActivateError::VhostUserFsSetup)?;
@ -471,6 +472,7 @@ impl VirtioDevice for Fs {
socket_path: self.socket_path.clone(),
server: false,
slave_req_handler,
inflight: None,
};
let paused = self.common.paused.clone();

View File

@ -11,7 +11,7 @@ use std::io;
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::sync::{atomic::AtomicBool, Arc, Barrier, Mutex};
use vhost::vhost_user::message::VhostUserVirtioFeatures;
use vhost::vhost_user::message::{VhostUserInflight, VhostUserVirtioFeatures};
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMasterReqHandler};
use vhost::Error as VhostError;
use vm_memory::{Error as MmapError, GuestAddressSpace, GuestMemoryAtomic};
@ -103,6 +103,10 @@ pub enum Error {
VhostUserGetConfig(VhostError),
/// Failed setting the configuration.
VhostUserSetConfig(VhostError),
/// Failed getting inflight shm log.
VhostUserGetInflight(VhostError),
/// Failed setting inflight shm log.
VhostUserSetInflight(VhostError),
/// Invalid used address.
UsedAddress,
/// Invalid features provided from vhost-user backend
@ -128,6 +132,12 @@ pub const DEFAULT_VIRTIO_FEATURES: u64 = 1 << VIRTIO_F_RING_INDIRECT_DESC
const HUP_CONNECTION_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
const SLAVE_REQ_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
#[derive(Default)]
pub struct Inflight {
pub info: VhostUserInflight,
pub fd: Option<std::fs::File>,
}
pub struct VhostUserEpollHandler<S: VhostUserMasterReqHandler> {
pub vu: Arc<Mutex<Master>>,
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
@ -141,6 +151,7 @@ pub struct VhostUserEpollHandler<S: VhostUserMasterReqHandler> {
pub socket_path: String,
pub server: bool,
pub slave_req_handler: Option<MasterReqHandler<S>>,
pub inflight: Option<Inflight>,
}
impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
@ -198,6 +209,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
self.acked_features,
self.acked_protocol_features,
&self.slave_req_handler,
self.inflight.as_mut(),
)
.map_err(|e| {
EpollHelperError::IoError(std::io::Error::new(

View File

@ -300,6 +300,7 @@ impl VirtioDevice for Net {
&interrupt_cb,
backend_acked_features,
&slave_req_handler,
None,
)
.map_err(ActivateError::VhostUserNetSetup)?;
@ -320,6 +321,7 @@ impl VirtioDevice for Net {
socket_path: self.socket_path.clone(),
server: self.server,
slave_req_handler: None,
inflight: None,
};
let paused = self.common.paused.clone();

View File

@ -3,6 +3,7 @@
use super::super::{Descriptor, Queue};
use super::{Error, Result};
use crate::vhost_user::Inflight;
use crate::{get_host_address_range, VirtioInterrupt, VirtioInterruptType};
use crate::{GuestMemoryMmap, GuestRegionMmap};
use std::convert::TryInto;
@ -12,7 +13,9 @@ use std::sync::Arc;
use std::thread::sleep;
use std::time::{Duration, Instant};
use std::vec::Vec;
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use vhost::vhost_user::message::{
VhostUserInflight, VhostUserProtocolFeatures, VhostUserVirtioFeatures,
};
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler};
use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData};
use vm_memory::{Address, Error as MmapError, GuestMemory, GuestMemoryRegion};
@ -100,6 +103,7 @@ pub fn negotiate_features_vhost_user(
Ok((acked_features, acked_protocol_features))
}
#[allow(clippy::too_many_arguments)]
pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
vu: &mut Master,
mem: &GuestMemoryMmap,
@ -108,6 +112,7 @@ pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
virtio_interrupt: &Arc<dyn VirtioInterrupt>,
acked_features: u64,
slave_req_handler: &Option<MasterReqHandler<S>>,
inflight: Option<&mut Inflight>,
) -> Result<()> {
vu.set_features(acked_features)
.map_err(Error::VhostUserSetFeatures)?;
@ -115,6 +120,26 @@ pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
// Let's first provide the memory table to the backend.
update_mem_table(vu, mem)?;
// Setup for inflight I/O tracking shared memory.
if let Some(inflight) = inflight {
if inflight.fd.is_none() {
let inflight_req_info = VhostUserInflight {
mmap_size: 0,
mmap_offset: 0,
num_queues: queues.len() as u16,
queue_size: queues[0].actual_size(),
};
let (info, fd) = vu
.get_inflight_fd(&inflight_req_info)
.map_err(Error::VhostUserGetInflight)?;
inflight.info = info;
inflight.fd = Some(fd);
}
// Unwrapping the inflight fd is safe here since we know it can't be None.
vu.set_inflight_fd(&inflight.info, inflight.fd.as_ref().unwrap().as_raw_fd())
.map_err(Error::VhostUserSetInflight)?;
}
for (queue_index, queue) in queues.into_iter().enumerate() {
let actual_size: usize = queue.actual_size().try_into().unwrap();
@ -194,6 +219,7 @@ pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>(
acked_features: u64,
acked_protocol_features: u64,
slave_req_handler: &Option<MasterReqHandler<S>>,
inflight: Option<&mut Inflight>,
) -> Result<()> {
vu.set_owner().map_err(Error::VhostUserSetOwner)?;
vu.get_features().map_err(Error::VhostUserGetFeatures)?;
@ -215,6 +241,7 @@ pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>(
virtio_interrupt,
acked_features,
slave_req_handler,
inflight,
)
}