From e80fab8d98f19029d2e24e09946ab08991b62a8b Mon Sep 17 00:00:00 2001 From: Liu Jiang Date: Wed, 1 Sep 2021 11:19:39 +0800 Subject: [PATCH] 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 --- src/backend.rs | 46 ++++++++++++++++++++++++++++++++++------------ src/event_loop.rs | 30 +++++++++++++++++++++--------- src/handler.rs | 45 ++++++++++++++++++++++++++++++++++----------- src/lib.rs | 20 +++++++++++++++----- 4 files changed, 104 insertions(+), 37 deletions(-) diff --git a/src/backend.rs b/src/backend.rs index 5f7ed8a..c4371f9 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -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" and "RefCell". -pub trait VhostUserBackend: Send + Sync + 'static { +pub trait VhostUserBackend: Send + Sync + 'static +where + V: VringT>, + B: Bitmap + 'static, +{ /// Get number of queues supported. fn num_queues(&self) -> usize; @@ -107,13 +112,17 @@ pub trait VhostUserBackend: Send + Sync + 'static { &self, device_event: u16, evset: epoll::Events, - vrings: &[VringRwLock>], + vrings: &[V], thread_id: usize, ) -> result::Result; } /// Trait without interior mutability for vhost user backend servers to implement concrete services. -pub trait VhostUserBackendMut: Send + Sync + 'static { +pub trait VhostUserBackendMut: Send + Sync + 'static +where + V: VringT>, + B: Bitmap + 'static, +{ /// Get number of queues supported. fn num_queues(&self) -> usize; @@ -186,12 +195,16 @@ pub trait VhostUserBackendMut: Send + Sync + 'static { &mut self, device_event: u16, evset: epoll::Events, - vrings: &[VringRwLock>], + vrings: &[V], thread_id: usize, ) -> result::Result; } -impl, B: Bitmap + 'static> VhostUserBackend for Arc { +impl, V, B> VhostUserBackend for Arc +where + V: VringT>, + B: Bitmap + 'static, +{ fn num_queues(&self) -> usize { self.deref().num_queues() } @@ -244,7 +257,7 @@ impl, B: Bitmap + 'static> VhostUserBackend for Arc &self, device_event: u16, evset: epoll::Events, - vrings: &[VringRwLock>], + vrings: &[V], thread_id: usize, ) -> Result { self.deref() @@ -252,7 +265,11 @@ impl, B: Bitmap + 'static> VhostUserBackend for Arc } } -impl, B: Bitmap + 'static> VhostUserBackend for Mutex { +impl, V, B> VhostUserBackend for Mutex +where + V: VringT>, + B: Bitmap + 'static, +{ fn num_queues(&self) -> usize { self.lock().unwrap().num_queues() } @@ -305,7 +322,7 @@ impl, B: Bitmap + 'static> VhostUserBackend for Mut &self, device_event: u16, evset: epoll::Events, - vrings: &[VringRwLock>], + vrings: &[V], thread_id: usize, ) -> Result { self.lock() @@ -314,7 +331,11 @@ impl, B: Bitmap + 'static> VhostUserBackend for Mut } } -impl, B: Bitmap + 'static> VhostUserBackend for RwLock { +impl, V, B> VhostUserBackend for RwLock +where + V: VringT>, + B: Bitmap + 'static, +{ fn num_queues(&self) -> usize { self.read().unwrap().num_queues() } @@ -367,7 +388,7 @@ impl, B: Bitmap + 'static> VhostUserBackend for RwL &self, device_event: u16, evset: epoll::Events, - vrings: &[VringRwLock>], + vrings: &[V], thread_id: usize, ) -> Result { self.write() @@ -379,6 +400,7 @@ impl, B: Bitmap + 'static> VhostUserBackend 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 for MockVhostBackend { fn num_queues(&self) -> usize { 2 } diff --git a/src/event_loop.rs b/src/event_loop.rs index aa65767..869df85 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -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 = std::result::Result; /// - 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, B: Bitmap + 'static> { +pub struct VringEpollHandler +where + S: VhostUserBackend, + V: VringT>, + B: Bitmap + 'static, +{ epoll_file: File, backend: S, - vrings: Vec>>, + vrings: Vec, thread_id: usize, exit_event_fd: Option, exit_event_id: Option, + phantom: PhantomData, } -impl, B: Bitmap + 'static> VringEpollHandler { +impl VringEpollHandler +where + S: VhostUserBackend, + V: VringT>, + B: Bitmap + 'static, +{ /// Create a `VringEpollHandler` instance. - pub(crate) fn new( - backend: S, - vrings: Vec>>, - thread_id: usize, - ) -> VringEpollResult { + pub(crate) fn new(backend: S, vrings: Vec, thread_id: usize) -> VringEpollResult { 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, B: Bitmap + 'static> VringEpollHandler { 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, B: Bitmap + 'static> VringEpollHandler { thread_id, exit_event_fd: None, exit_event_id: None, + phantom: PhantomData, }, }; @@ -225,6 +236,7 @@ impl, B: Bitmap + 'static> VringEpollHandler { #[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}; diff --git a/src/handler.rs b/src/handler.rs index 24e4ee8..dca7f19 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -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, B: Bitmap + 'static> { +pub struct VhostUserHandler +where + S: VhostUserBackend, + V: VringT>, + B: Bitmap + 'static, +{ backend: S, - handlers: Vec>>, + handlers: Vec>>, owned: bool, features_acked: bool, acked_features: u64, @@ -82,11 +87,16 @@ pub struct VhostUserHandler, B: Bitmap + 'static> { queues_per_thread: Vec, mappings: Vec, atomic_mem: GM, - vrings: Vec>>, + vrings: Vec, worker_threads: Vec>>, } -impl + Clone, B: Bitmap + Clone + Send + Sync> VhostUserHandler { +impl VhostUserHandler +where + S: VhostUserBackend + Clone, + V: VringT> + Clone + Send + Sync + 'static, + B: Bitmap + Clone + Send + Sync, +{ pub(crate) fn new(backend: S, atomic_mem: GM) -> VhostUserHandlerResult { let num_queues = backend.num_queues(); let max_queue_size = backend.max_queue_size(); @@ -94,7 +104,7 @@ impl + 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 + Clone, B: Bitmap + Clone + Send + Sync> VhostUserH } } -impl, B: Bitmap> VhostUserHandler { - pub(crate) fn get_epoll_handlers(&self) -> Vec>> { +impl VhostUserHandler +where + S: VhostUserBackend, + V: VringT>, + B: Bitmap, +{ + pub(crate) fn get_epoll_handlers(&self) -> Vec>> { self.handlers.clone() } @@ -162,8 +177,11 @@ impl, B: Bitmap> VhostUserHandler { } } -impl, B: NewBitmap + Clone> VhostUserSlaveReqHandlerMut - for VhostUserHandler +impl VhostUserSlaveReqHandlerMut for VhostUserHandler +where + S: VhostUserBackend, + V: VringT>, + B: NewBitmap + Clone, { fn set_owner(&mut self) -> VhostUserResult<()> { if self.owned { @@ -538,7 +556,12 @@ impl, B: NewBitmap + Clone> VhostUserSlaveReqHandlerMut } } -impl, B: Bitmap> Drop for VhostUserHandler { +impl Drop for VhostUserHandler +where + S: VhostUserBackend, + V: VringT>, + B: Bitmap, +{ fn drop(&mut self) { // Signal all working threads to exit. self.send_exit_event(); diff --git a/src/lib.rs b/src/lib.rs index 6d8a271..db152a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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>` to simplify code. type GM = GuestMemoryAtomic>; @@ -73,13 +73,23 @@ pub type Result = result::Result; /// /// 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, B: Bitmap + 'static = ()> { +pub struct VhostUserDaemon +where + S: VhostUserBackend, + V: VringT> + Clone + Send + Sync + 'static, + B: Bitmap + 'static, +{ name: String, - handler: Arc>>, + handler: Arc>>, main_thread: Option>>, } -impl + Clone, B: NewBitmap + Clone + Send + Sync> VhostUserDaemon { +impl VhostUserDaemon +where + S: VhostUserBackend + Clone, + V: VringT> + 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 + 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>> { + pub fn get_epoll_handlers(&self) -> Vec>> { self.handler.lock().unwrap().get_epoll_handlers() } }