vring: add generic parameter for VringT

Enhance VhostUserBackend, VhostUserBackendMut, VringEpollHandler,
VhostUserHandler and VhostUserDaemon to support generic type
`V: VringT', so clients could choose different VringT implementations.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2021-09-01 11:19:39 +08:00 committed by Jiang Liu
parent ed929c0cbd
commit e80fab8d98
4 changed files with 104 additions and 37 deletions

View file

@ -28,13 +28,18 @@ use vhost::vhost_user::SlaveFsCacheReq;
use vm_memory::bitmap::Bitmap;
use vmm_sys_util::eventfd::EventFd;
use super::{VringRwLock, GM};
use super::vring::VringT;
use super::GM;
/// Trait with interior mutability for vhost user backend servers to implement concrete services.
///
/// To support multi-threading and asynchronous IO, we enforce `the Send + Sync + 'static`.
/// So there's no plan for support of "Rc<T>" and "RefCell<T>".
pub trait VhostUserBackend<B: Bitmap + 'static = ()>: Send + Sync + 'static {
pub trait VhostUserBackend<V, B = ()>: Send + Sync + 'static
where
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
/// Get number of queues supported.
fn num_queues(&self) -> usize;
@ -107,13 +112,17 @@ pub trait VhostUserBackend<B: Bitmap + 'static = ()>: Send + Sync + 'static {
&self,
device_event: u16,
evset: epoll::Events,
vrings: &[VringRwLock<GM<B>>],
vrings: &[V],
thread_id: usize,
) -> result::Result<bool, io::Error>;
}
/// Trait without interior mutability for vhost user backend servers to implement concrete services.
pub trait VhostUserBackendMut<B: Bitmap + 'static = ()>: Send + Sync + 'static {
pub trait VhostUserBackendMut<V, B = ()>: Send + Sync + 'static
where
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
/// Get number of queues supported.
fn num_queues(&self) -> usize;
@ -186,12 +195,16 @@ pub trait VhostUserBackendMut<B: Bitmap + 'static = ()>: Send + Sync + 'static {
&mut self,
device_event: u16,
evset: epoll::Events,
vrings: &[VringRwLock<GM<B>>],
vrings: &[V],
thread_id: usize,
) -> result::Result<bool, io::Error>;
}
impl<T: VhostUserBackend<B>, B: Bitmap + 'static> VhostUserBackend<B> for Arc<T> {
impl<T: VhostUserBackend<V, B>, V, B> VhostUserBackend<V, B> for Arc<T>
where
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
fn num_queues(&self) -> usize {
self.deref().num_queues()
}
@ -244,7 +257,7 @@ impl<T: VhostUserBackend<B>, B: Bitmap + 'static> VhostUserBackend<B> for Arc<T>
&self,
device_event: u16,
evset: epoll::Events,
vrings: &[VringRwLock<GM<B>>],
vrings: &[V],
thread_id: usize,
) -> Result<bool, io::Error> {
self.deref()
@ -252,7 +265,11 @@ impl<T: VhostUserBackend<B>, B: Bitmap + 'static> VhostUserBackend<B> for Arc<T>
}
}
impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for Mutex<T> {
impl<T: VhostUserBackendMut<V, B>, V, B> VhostUserBackend<V, B> for Mutex<T>
where
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
fn num_queues(&self) -> usize {
self.lock().unwrap().num_queues()
}
@ -305,7 +322,7 @@ impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for Mut
&self,
device_event: u16,
evset: epoll::Events,
vrings: &[VringRwLock<GM<B>>],
vrings: &[V],
thread_id: usize,
) -> Result<bool, io::Error> {
self.lock()
@ -314,7 +331,11 @@ impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for Mut
}
}
impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for RwLock<T> {
impl<T: VhostUserBackendMut<V, B>, V, B> VhostUserBackend<V, B> for RwLock<T>
where
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
fn num_queues(&self) -> usize {
self.read().unwrap().num_queues()
}
@ -367,7 +388,7 @@ impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for RwL
&self,
device_event: u16,
evset: epoll::Events,
vrings: &[VringRwLock<GM<B>>],
vrings: &[V],
thread_id: usize,
) -> Result<bool, io::Error> {
self.write()
@ -379,6 +400,7 @@ impl<T: VhostUserBackendMut<B>, B: Bitmap + 'static> VhostUserBackend<B> for RwL
#[cfg(test)]
pub mod tests {
use super::*;
use crate::VringRwLock;
use epoll::Events;
use std::io::Error;
use std::sync::Mutex;
@ -400,7 +422,7 @@ pub mod tests {
}
}
impl VhostUserBackendMut<()> for MockVhostBackend {
impl VhostUserBackendMut<VringRwLock, ()> for MockVhostBackend {
fn num_queues(&self) -> usize {
2
}

View file

@ -6,14 +6,16 @@
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io;
use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::result;
use vm_memory::bitmap::Bitmap;
use vmm_sys_util::eventfd::EventFd;
use super::backend::VhostUserBackend;
use super::vring::VringT;
use super::{VhostUserBackend, VringRwLock, GM};
use super::GM;
/// Errors related to vring epoll event handling.
#[derive(Debug)]
@ -57,22 +59,29 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
/// - add file descriptors to be monitored by the epoll fd
/// - remove registered file descriptors from the epoll fd
/// - run the event loop to handle pending events on the epoll fd
pub struct VringEpollHandler<S: VhostUserBackend<B>, B: Bitmap + 'static> {
pub struct VringEpollHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
epoll_file: File,
backend: S,
vrings: Vec<VringRwLock<GM<B>>>,
vrings: Vec<V>,
thread_id: usize,
exit_event_fd: Option<EventFd>,
exit_event_id: Option<u16>,
phantom: PhantomData<B>,
}
impl<S: VhostUserBackend<B>, B: Bitmap + 'static> VringEpollHandler<S, B> {
impl<S, V, B> VringEpollHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
/// Create a `VringEpollHandler` instance.
pub(crate) fn new(
backend: S,
vrings: Vec<VringRwLock<GM<B>>>,
thread_id: usize,
) -> VringEpollResult<Self> {
pub(crate) fn new(backend: S, vrings: Vec<V>, thread_id: usize) -> VringEpollResult<Self> {
let epoll_fd = epoll::create(true).map_err(VringEpollError::EpollCreateFd)?;
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
@ -93,6 +102,7 @@ impl<S: VhostUserBackend<B>, B: Bitmap + 'static> VringEpollHandler<S, B> {
thread_id,
exit_event_fd: Some(exit_event_fd),
exit_event_id: Some(exit_event_id),
phantom: PhantomData,
}
}
None => VringEpollHandler {
@ -102,6 +112,7 @@ impl<S: VhostUserBackend<B>, B: Bitmap + 'static> VringEpollHandler<S, B> {
thread_id,
exit_event_fd: None,
exit_event_id: None,
phantom: PhantomData,
},
};
@ -225,6 +236,7 @@ impl<S: VhostUserBackend<B>, B: Bitmap + 'static> VringEpollHandler<S, B> {
#[cfg(test)]
mod tests {
use super::super::backend::tests::MockVhostBackend;
use super::super::vring::VringRwLock;
use super::*;
use std::sync::{Arc, Mutex};
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};

View file

@ -29,7 +29,7 @@ use vm_memory::{
use super::backend::VhostUserBackend;
use super::event_loop::VringEpollHandler;
use super::event_loop::{VringEpollError, VringEpollResult};
use super::vring::{VringRwLock, VringT};
use super::vring::VringT;
use super::GM;
const MAX_MEM_SLOTS: u64 = 32;
@ -70,9 +70,14 @@ struct AddrMapping {
gpa_base: u64,
}
pub struct VhostUserHandler<S: VhostUserBackend<B>, B: Bitmap + 'static> {
pub struct VhostUserHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: Bitmap + 'static,
{
backend: S,
handlers: Vec<Arc<VringEpollHandler<S, B>>>,
handlers: Vec<Arc<VringEpollHandler<S, V, B>>>,
owned: bool,
features_acked: bool,
acked_features: u64,
@ -82,11 +87,16 @@ pub struct VhostUserHandler<S: VhostUserBackend<B>, B: Bitmap + 'static> {
queues_per_thread: Vec<u64>,
mappings: Vec<AddrMapping>,
atomic_mem: GM<B>,
vrings: Vec<VringRwLock<GM<B>>>,
vrings: Vec<V>,
worker_threads: Vec<thread::JoinHandle<VringEpollResult<()>>>,
}
impl<S: VhostUserBackend<B> + Clone, B: Bitmap + Clone + Send + Sync> VhostUserHandler<S, B> {
impl<S, V, B> VhostUserHandler<S, V, B>
where
S: VhostUserBackend<V, B> + Clone,
V: VringT<GM<B>> + Clone + Send + Sync + 'static,
B: Bitmap + Clone + Send + Sync,
{
pub(crate) fn new(backend: S, atomic_mem: GM<B>) -> VhostUserHandlerResult<Self> {
let num_queues = backend.num_queues();
let max_queue_size = backend.max_queue_size();
@ -94,7 +104,7 @@ impl<S: VhostUserBackend<B> + Clone, B: Bitmap + Clone + Send + Sync> VhostUserH
let mut vrings = Vec::new();
for _ in 0..num_queues {
let vring = VringRwLock::new(atomic_mem.clone(), max_queue_size as u16);
let vring = V::new(atomic_mem.clone(), max_queue_size as u16);
vrings.push(vring);
}
@ -140,8 +150,13 @@ impl<S: VhostUserBackend<B> + Clone, B: Bitmap + Clone + Send + Sync> VhostUserH
}
}
impl<S: VhostUserBackend<B>, B: Bitmap> VhostUserHandler<S, B> {
pub(crate) fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, B>>> {
impl<S, V, B> VhostUserHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: Bitmap,
{
pub(crate) fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, V, B>>> {
self.handlers.clone()
}
@ -162,8 +177,11 @@ impl<S: VhostUserBackend<B>, B: Bitmap> VhostUserHandler<S, B> {
}
}
impl<S: VhostUserBackend<B>, B: NewBitmap + Clone> VhostUserSlaveReqHandlerMut
for VhostUserHandler<S, B>
impl<S, V, B> VhostUserSlaveReqHandlerMut for VhostUserHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: NewBitmap + Clone,
{
fn set_owner(&mut self) -> VhostUserResult<()> {
if self.owned {
@ -538,7 +556,12 @@ impl<S: VhostUserBackend<B>, B: NewBitmap + Clone> VhostUserSlaveReqHandlerMut
}
}
impl<S: VhostUserBackend<B>, B: Bitmap> Drop for VhostUserHandler<S, B> {
impl<S, V, B> Drop for VhostUserHandler<S, V, B>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>>,
B: Bitmap,
{
fn drop(&mut self) {
// Signal all working threads to exit.
self.send_exit_event();

View file

@ -31,7 +31,7 @@ mod handler;
pub use self::handler::VhostUserHandlerError;
mod vring;
pub use self::vring::{VringRwLock, VringState};
pub use self::vring::{VringMutex, VringRwLock, VringState, VringT};
/// An alias for `GuestMemoryAtomic<GuestMemoryMmap<B>>` to simplify code.
type GM<B> = GuestMemoryAtomic<GuestMemoryMmap<B>>;
@ -73,13 +73,23 @@ pub type Result<T> = result::Result<T, Error>;
///
/// This structure is the public API the backend is allowed to interact with in order to run
/// a fully functional vhost-user daemon.
pub struct VhostUserDaemon<S: VhostUserBackend<B>, B: Bitmap + 'static = ()> {
pub struct VhostUserDaemon<S, V, B = ()>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>> + Clone + Send + Sync + 'static,
B: Bitmap + 'static,
{
name: String,
handler: Arc<Mutex<VhostUserHandler<S, B>>>,
handler: Arc<Mutex<VhostUserHandler<S, V, B>>>,
main_thread: Option<thread::JoinHandle<Result<()>>>,
}
impl<S: VhostUserBackend<B> + Clone, B: NewBitmap + Clone + Send + Sync> VhostUserDaemon<S, B> {
impl<S, V, B> VhostUserDaemon<S, V, B>
where
S: VhostUserBackend<V, B> + Clone,
V: VringT<GM<B>> + Clone + Send + Sync + 'static,
B: NewBitmap + Clone + Send + Sync,
{
/// Create the daemon instance, providing the backend implementation of `VhostUserBackend`.
///
/// Under the hood, this will start a dedicated thread responsible for listening onto
@ -144,7 +154,7 @@ impl<S: VhostUserBackend<B> + Clone, B: NewBitmap + Clone + Send + Sync> VhostUs
///
/// This is necessary to perform further actions like registering and unregistering some extra
/// event file descriptors.
pub fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, B>>> {
pub fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, V, B>>> {
self.handler.lock().unwrap().get_epoll_handlers()
}
}