Skip to content
This repository was archived by the owner on Oct 24, 2022. It is now read-only.

Refactor vring abstraction #30

Merged
merged 4 commits into from
Sep 7, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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>
  • Loading branch information
jiangliu committed Sep 7, 2021
commit 30fa5e4ae3b3d416bb9723dc1ea78ed1237fa93c
46 changes: 34 additions & 12 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -244,15 +257,19 @@ 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()
.handle_event(device_event, evset, vrings, thread_id)
}
}

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()
}
Expand Down Expand Up @@ -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()
Expand All @@ -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()
}
Expand Down Expand Up @@ -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()
Expand All @@ -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;
Expand All @@ -400,7 +422,7 @@ pub mod tests {
}
}

impl VhostUserBackendMut<()> for MockVhostBackend {
impl VhostUserBackendMut<VringRwLock, ()> for MockVhostBackend {
fn num_queues(&self) -> usize {
2
}
Expand Down
30 changes: 21 additions & 9 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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) };

Expand All @@ -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 {
Expand All @@ -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,
},
};

Expand Down Expand Up @@ -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};
Expand Down
45 changes: 34 additions & 11 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -82,19 +87,24 @@ 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();
let queues_per_thread = backend.queues_per_thread();

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);
}

Expand Down Expand Up @@ -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()
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down
20 changes: 15 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
}
Expand Down