mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-23 13:05:45 +00:00
vhost_user_fs: Add support for EVENT_IDX
Now that Queue supports EVENT_IDX, expose the feature and add support for it in vhost_user_fs. Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
parent
eae4f1d249
commit
1c5562b656
@ -13,19 +13,23 @@ use clap::{App, Arg};
|
|||||||
use epoll;
|
use epoll;
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use std::num::Wrapping;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::{convert, error, fmt, io, process};
|
use std::{convert, error, fmt, io, process};
|
||||||
|
|
||||||
use vhost_rs::vhost_user::message::*;
|
use vhost_rs::vhost_user::message::*;
|
||||||
use vhost_rs::vhost_user::SlaveFsCacheReq;
|
use vhost_rs::vhost_user::SlaveFsCacheReq;
|
||||||
use vhost_user_backend::{VhostUserBackend, VhostUserDaemon, Vring};
|
use vhost_user_backend::{VhostUserBackend, VhostUserDaemon, Vring};
|
||||||
|
use vhost_user_fs::descriptor_utils::Error as VufDescriptorError;
|
||||||
use vhost_user_fs::descriptor_utils::{Reader, Writer};
|
use vhost_user_fs::descriptor_utils::{Reader, Writer};
|
||||||
use vhost_user_fs::filesystem::FileSystem;
|
use vhost_user_fs::filesystem::FileSystem;
|
||||||
use vhost_user_fs::passthrough::{self, PassthroughFs};
|
use vhost_user_fs::passthrough::{self, PassthroughFs};
|
||||||
use vhost_user_fs::server::Server;
|
use vhost_user_fs::server::Server;
|
||||||
use vhost_user_fs::Error as VhostUserFsError;
|
use vhost_user_fs::Error as VhostUserFsError;
|
||||||
use virtio_bindings::bindings::virtio_net::*;
|
use virtio_bindings::bindings::virtio_net::*;
|
||||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_INDIRECT_DESC;
|
use virtio_bindings::bindings::virtio_ring::{
|
||||||
|
VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC,
|
||||||
|
};
|
||||||
use vm_memory::GuestMemoryMmap;
|
use vm_memory::GuestMemoryMmap;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
@ -54,6 +58,12 @@ enum Error {
|
|||||||
NoMemoryConfigured,
|
NoMemoryConfigured,
|
||||||
/// Processing queue failed.
|
/// Processing queue failed.
|
||||||
ProcessQueue(VhostUserFsError),
|
ProcessQueue(VhostUserFsError),
|
||||||
|
/// Creating a queue reader failed.
|
||||||
|
QueueReader(VufDescriptorError),
|
||||||
|
/// Creating a queue writer failed.
|
||||||
|
QueueWriter(VufDescriptorError),
|
||||||
|
/// Signaling queue failed.
|
||||||
|
SignalQueue(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@ -76,6 +86,7 @@ struct VhostUserFsBackend<F: FileSystem + Send + Sync + 'static> {
|
|||||||
server: Arc<Server<F>>,
|
server: Arc<Server<F>>,
|
||||||
// handle request from slave to master
|
// handle request from slave to master
|
||||||
vu_req: Option<SlaveFsCacheReq>,
|
vu_req: Option<SlaveFsCacheReq>,
|
||||||
|
event_idx: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: FileSystem + Send + Sync + 'static> Clone for VhostUserFsBackend<F> {
|
impl<F: FileSystem + Send + Sync + 'static> Clone for VhostUserFsBackend<F> {
|
||||||
@ -85,6 +96,7 @@ impl<F: FileSystem + Send + Sync + 'static> Clone for VhostUserFsBackend<F> {
|
|||||||
kill_evt: self.kill_evt.try_clone().unwrap(),
|
kill_evt: self.kill_evt.try_clone().unwrap(),
|
||||||
server: self.server.clone(),
|
server: self.server.clone(),
|
||||||
vu_req: self.vu_req.clone(),
|
vu_req: self.vu_req.clone(),
|
||||||
|
event_idx: self.event_idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,36 +108,39 @@ impl<F: FileSystem + Send + Sync + 'static> VhostUserFsBackend<F> {
|
|||||||
kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?,
|
kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?,
|
||||||
server: Arc::new(Server::new(fs)),
|
server: Arc::new(Server::new(fs)),
|
||||||
vu_req: None,
|
vu_req: None,
|
||||||
|
event_idx: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_queue(&mut self, vring: &mut Vring) -> Result<()> {
|
fn process_queue(&mut self, vring: &mut Vring) -> Result<bool> {
|
||||||
|
let mut used_any = false;
|
||||||
let mem = self.mem.as_ref().ok_or(Error::NoMemoryConfigured)?;
|
let mem = self.mem.as_ref().ok_or(Error::NoMemoryConfigured)?;
|
||||||
|
|
||||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE];
|
|
||||||
let mut used_count = 0;
|
|
||||||
while let Some(avail_desc) = vring.mut_queue().iter(&mem).next() {
|
while let Some(avail_desc) = vring.mut_queue().iter(&mem).next() {
|
||||||
let head_index = avail_desc.index;
|
let head_index = avail_desc.index;
|
||||||
let reader = Reader::new(mem, avail_desc.clone()).unwrap();
|
let reader = Reader::new(mem, avail_desc.clone()).map_err(Error::QueueReader)?;
|
||||||
let writer = Writer::new(mem, avail_desc.clone()).unwrap();
|
let writer = Writer::new(mem, avail_desc.clone()).map_err(Error::QueueWriter)?;
|
||||||
|
|
||||||
let total = self
|
self.server
|
||||||
.server
|
|
||||||
.handle_message(reader, writer, self.vu_req.as_mut())
|
.handle_message(reader, writer, self.vu_req.as_mut())
|
||||||
.map_err(Error::ProcessQueue)?;
|
.map_err(Error::ProcessQueue)?;
|
||||||
|
if self.event_idx {
|
||||||
used_desc_heads[used_count] = (head_index, total);
|
if let Some(used_idx) = vring.mut_queue().add_used(mem, head_index, 0) {
|
||||||
used_count += 1;
|
let used_event = vring.mut_queue().get_used_event(mem);
|
||||||
|
if vring.needs_notification(Wrapping(used_idx), used_event) {
|
||||||
|
vring.signal_used_queue().map_err(Error::SignalQueue)?;
|
||||||
|
}
|
||||||
|
used_any = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vring.mut_queue().add_used(mem, head_index, 0);
|
||||||
|
vring.signal_used_queue().map_err(Error::SignalQueue)?;
|
||||||
|
used_any = true;
|
||||||
|
}
|
||||||
|
vring.signal_used_queue().map_err(Error::SignalQueue)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if used_count > 0 {
|
Ok(used_any)
|
||||||
for &(desc_index, _) in &used_desc_heads[..used_count] {
|
|
||||||
vring.mut_queue().add_used(&mem, desc_index, 0);
|
|
||||||
}
|
|
||||||
vring.signal_used_queue().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +156,7 @@ impl<F: FileSystem + Send + Sync + 'static> VhostUserBackend for VhostUserFsBack
|
|||||||
fn features(&self) -> u64 {
|
fn features(&self) -> u64 {
|
||||||
1 << VIRTIO_F_VERSION_1
|
1 << VIRTIO_F_VERSION_1
|
||||||
| 1 << VIRTIO_RING_F_INDIRECT_DESC
|
| 1 << VIRTIO_RING_F_INDIRECT_DESC
|
||||||
|
| 1 << VIRTIO_RING_F_EVENT_IDX
|
||||||
| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
|
| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +164,9 @@ impl<F: FileSystem + Send + Sync + 'static> VhostUserBackend for VhostUserFsBack
|
|||||||
VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::SLAVE_REQ
|
VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::SLAVE_REQ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_event_idx(&mut self, _enabled: bool) {}
|
fn set_event_idx(&mut self, enabled: bool) {
|
||||||
|
self.event_idx = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
fn update_memory(&mut self, mem: GuestMemoryMmap) -> VhostUserBackendResult<()> {
|
fn update_memory(&mut self, mem: GuestMemoryMmap) -> VhostUserBackendResult<()> {
|
||||||
self.mem = Some(mem);
|
self.mem = Some(mem);
|
||||||
@ -172,8 +190,24 @@ impl<F: FileSystem + Send + Sync + 'static> VhostUserBackend for VhostUserFsBack
|
|||||||
REQ_QUEUE_EVENT => {
|
REQ_QUEUE_EVENT => {
|
||||||
debug!("REQ_QUEUE_EVENT");
|
debug!("REQ_QUEUE_EVENT");
|
||||||
let mut vring = vrings[1].write().unwrap();
|
let mut vring = vrings[1].write().unwrap();
|
||||||
|
if self.event_idx {
|
||||||
|
// vm-virtio's Queue implementation only checks avail_index
|
||||||
|
// once, so to properly support EVENT_IDX we need to keep
|
||||||
|
// calling process_queue() until it stops finding new
|
||||||
|
// requests on the queue.
|
||||||
|
loop {
|
||||||
|
vring.mut_queue().update_avail_event(
|
||||||
|
self.mem.as_ref().ok_or(Error::NoMemoryConfigured)?,
|
||||||
|
);
|
||||||
|
if !self.process_queue(&mut vring)? {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Without EVENT_IDX, a single call is enough.
|
||||||
self.process_queue(&mut vring)?;
|
self.process_queue(&mut vring)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => return Err(Error::HandleEventUnknownEvent.into()),
|
_ => return Err(Error::HandleEventUnknownEvent.into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user