mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
vm-virtio: fs: Factorize vhost-user setup
This patch factorizes the existing virtio-fs code by relying onto the common code part of the vhost_user module in the vm-virtio crate. In details, it factorizes the vhost-user setup, and reuses the error types defined by the module instead of defining its own types. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
56cad00f2e
commit
b7d3ad9063
@ -47,7 +47,6 @@ const DEVICE_FEATURES_OK: u32 = 0x08;
|
||||
const DEVICE_FAILED: u32 = 0x80;
|
||||
|
||||
const VIRTIO_F_VERSION_1: u32 = 32;
|
||||
const VIRTIO_F_VERSION_1_BITMASK: u64 = 1 << VIRTIO_F_VERSION_1;
|
||||
|
||||
// Types taken from linux/virtio_ids.h
|
||||
#[derive(Copy, Clone)]
|
||||
@ -124,7 +123,7 @@ pub enum ActivateError {
|
||||
/// Failed to create Vhost-user interrupt eventfd
|
||||
VhostIrqCreate,
|
||||
/// Failed to setup vhost-user daemon.
|
||||
VhostUserSetup(vhost_user::fs::Error),
|
||||
VhostUserSetup(vhost_user::Error),
|
||||
/// Failed to setup vhost-user daemon.
|
||||
VhostUserNetSetup(vhost_user::Error),
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::vu_common_ctrl::setup_vhost_user;
|
||||
use super::{Error, Result};
|
||||
use crate::{
|
||||
ActivateError, ActivateResult, Queue, VirtioDevice, VirtioDeviceType,
|
||||
VirtioInterrupt, VirtioInterruptType, VirtioSharedMemoryList,
|
||||
VIRTIO_F_VERSION_1_BITMASK,
|
||||
ActivateError, ActivateResult, Queue, VirtioDevice, VirtioDeviceType, VirtioInterrupt,
|
||||
VirtioInterruptType, VirtioSharedMemoryList, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use epoll;
|
||||
use libc::{self, EFD_NONBLOCK};
|
||||
@ -22,8 +22,8 @@ use vhost_rs::vhost_user::message::{
|
||||
use vhost_rs::vhost_user::{
|
||||
HandlerResult, Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler,
|
||||
};
|
||||
use vhost_rs::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData};
|
||||
use vm_memory::{Address, Error as MmapError, GuestMemory, GuestMemoryMmap, GuestMemoryRegion};
|
||||
use vhost_rs::VhostBackend;
|
||||
use vm_memory::GuestMemoryMmap;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
const CONFIG_SPACE_TAG_SIZE: usize = 36;
|
||||
@ -31,73 +31,6 @@ const CONFIG_SPACE_NUM_QUEUES_SIZE: usize = 4;
|
||||
const CONFIG_SPACE_SIZE: usize = CONFIG_SPACE_TAG_SIZE + CONFIG_SPACE_NUM_QUEUES_SIZE;
|
||||
const NUM_QUEUE_OFFSET: usize = 1;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// common
|
||||
|
||||
/// Invalid descriptor table address.
|
||||
DescriptorTableAddress,
|
||||
/// Invalid used address.
|
||||
UsedAddress,
|
||||
/// Invalid available address.
|
||||
AvailAddress,
|
||||
|
||||
/// vhost
|
||||
|
||||
/// Creating kill eventfd failed.
|
||||
CreateKillEventFd(io::Error),
|
||||
/// Cloning kill eventfd failed.
|
||||
CloneKillEventFd(io::Error),
|
||||
/// Error while polling for events.
|
||||
PollError(io::Error),
|
||||
/// Failed to create irq eventfd.
|
||||
IrqEventCreate(io::Error),
|
||||
/// Failed to read vhost eventfd.
|
||||
VhostIrqRead(io::Error),
|
||||
|
||||
/// vhost-user
|
||||
|
||||
/// Connection to socket failed.
|
||||
VhostUserConnect(vhost_rs::Error),
|
||||
/// Get features failed.
|
||||
VhostUserGetFeatures(vhost_rs::Error),
|
||||
/// Get protocol features failed.
|
||||
VhostUserGetProtocolFeatures(vhost_rs::Error),
|
||||
/// Set owner failed.
|
||||
VhostUserSetOwner(vhost_rs::Error),
|
||||
/// Set features failed.
|
||||
VhostUserSetFeatures(vhost_rs::Error),
|
||||
/// Set protocol features failed.
|
||||
VhostUserSetProtocolFeatures(vhost_rs::Error),
|
||||
/// Set mem table failed.
|
||||
VhostUserSetMemTable(vhost_rs::Error),
|
||||
/// Set vring num failed.
|
||||
VhostUserSetVringNum(vhost_rs::Error),
|
||||
/// Set vring addr failed.
|
||||
VhostUserSetVringAddr(vhost_rs::Error),
|
||||
/// Set vring base failed.
|
||||
VhostUserSetVringBase(vhost_rs::Error),
|
||||
/// Set vring call failed.
|
||||
VhostUserSetVringCall(vhost_rs::Error),
|
||||
/// Set vring kick failed.
|
||||
VhostUserSetVringKick(vhost_rs::Error),
|
||||
/// Set slave request fd failed.
|
||||
VhostUserSetSlaveRequestFd(vhost_rs::Error),
|
||||
|
||||
/// Invalid features provided from vhost-user backend.
|
||||
InvalidFeatures,
|
||||
|
||||
/// Missing file descriptor.
|
||||
FdMissing,
|
||||
|
||||
/// Failure going through memory regions.
|
||||
MemoryRegions(MmapError),
|
||||
|
||||
/// Failed to create the master request handler from slave.
|
||||
MasterReqHandlerCreation(vhost_rs::vhost_user::Error),
|
||||
}
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
struct SlaveReqHandler {
|
||||
cache_size: u64,
|
||||
mmap_cache_addr: u64,
|
||||
@ -185,9 +118,9 @@ struct FsEpollHandler<S: VhostUserMasterReqHandler> {
|
||||
}
|
||||
|
||||
impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
fn run(&mut self) -> result::Result<(), DeviceError> {
|
||||
fn run(&mut self) -> result::Result<(), Error> {
|
||||
// Create the epoll file descriptor
|
||||
let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?;
|
||||
let epoll_fd = epoll::create(true).map_err(Error::EpollCreateFd)?;
|
||||
|
||||
for (evt_index, vu_call_evt_queue) in self.vu_call_evt_queue_list.iter().enumerate() {
|
||||
// Add events
|
||||
@ -197,7 +130,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
vu_call_evt_queue.0.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, evt_index as u64),
|
||||
)
|
||||
.map_err(DeviceError::EpollCtl)?;
|
||||
.map_err(Error::EpollCtl)?;
|
||||
}
|
||||
|
||||
let kill_evt_index = self.vu_call_evt_queue_list.len();
|
||||
@ -207,7 +140,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
self.kill_evt.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, kill_evt_index as u64),
|
||||
)
|
||||
.map_err(DeviceError::EpollCtl)?;
|
||||
.map_err(Error::EpollCtl)?;
|
||||
|
||||
let slave_evt_index = if let Some(self_req_handler) = &self.slave_req_handler {
|
||||
let index = kill_evt_index + 1;
|
||||
@ -217,7 +150,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
self_req_handler.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, index as u64),
|
||||
)
|
||||
.map_err(DeviceError::EpollCtl)?;
|
||||
.map_err(Error::EpollCtl)?;
|
||||
|
||||
Some(index)
|
||||
} else {
|
||||
@ -241,7 +174,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
// appropriate to retry, by calling into epoll_wait().
|
||||
continue;
|
||||
}
|
||||
return Err(DeviceError::EpollWait(e));
|
||||
return Err(Error::EpollWait(e));
|
||||
}
|
||||
};
|
||||
|
||||
@ -259,7 +192,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
) {
|
||||
error!(
|
||||
"Failed to signal used queue: {:?}",
|
||||
DeviceError::FailedSignalingUsedQueue(e)
|
||||
Error::FailedSignalingUsedQueue(e)
|
||||
);
|
||||
break 'epoll;
|
||||
}
|
||||
@ -272,7 +205,7 @@ impl<S: VhostUserMasterReqHandler> FsEpollHandler<S> {
|
||||
if let Some(slave_req_handler) = self.slave_req_handler.as_mut() {
|
||||
slave_req_handler
|
||||
.handle_request()
|
||||
.map_err(DeviceError::VhostUserSlaveRequest)?;
|
||||
.map_err(Error::VhostUserSlaveRequest)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -307,26 +240,36 @@ impl Fs {
|
||||
cache: Option<(VirtioSharedMemoryList, u64)>,
|
||||
) -> Result<Fs> {
|
||||
let mut slave_req_support = false;
|
||||
|
||||
// Calculate the actual number of queues needed.
|
||||
let num_queues = NUM_QUEUE_OFFSET + req_num_queues;
|
||||
|
||||
// Connect to the vhost-user socket.
|
||||
let mut master =
|
||||
Master::connect(path, num_queues as u64).map_err(Error::VhostUserConnect)?;
|
||||
// Retrieve available features only when connecting the first time.
|
||||
let mut avail_features = master.get_features().map_err(Error::VhostUserGetFeatures)?;
|
||||
// Let only ack features we expect, that is VIRTIO_F_VERSION_1.
|
||||
if (avail_features & VIRTIO_F_VERSION_1_BITMASK) != VIRTIO_F_VERSION_1_BITMASK {
|
||||
return Err(Error::InvalidFeatures);
|
||||
}
|
||||
avail_features =
|
||||
VIRTIO_F_VERSION_1_BITMASK | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
Master::connect(path, num_queues as u64).map_err(Error::VhostUserCreateMaster)?;
|
||||
|
||||
// Filling device and vring features VMM supports.
|
||||
let mut avail_features =
|
||||
1 << VIRTIO_F_VERSION_1 | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
|
||||
// Set vhost-user owner.
|
||||
master.set_owner().map_err(Error::VhostUserSetOwner)?;
|
||||
|
||||
// Get features from backend, do negotiation to get a feature collection which
|
||||
// both VMM and backend support.
|
||||
let backend_features = master.get_features().map_err(Error::VhostUserGetFeatures)?;
|
||||
avail_features &= backend_features;
|
||||
// Set features back is required by the vhost crate mechanism, since the
|
||||
// later vhost call will check if features is filled in master before execution.
|
||||
master
|
||||
.set_features(avail_features)
|
||||
.map_err(Error::VhostUserSetFeatures)?;
|
||||
|
||||
// Identify if protocol features are supported by the slave.
|
||||
if (avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits())
|
||||
== VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
|
||||
{
|
||||
let mut acked_features = 0;
|
||||
if avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 {
|
||||
acked_features |= VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
|
||||
let mut protocol_features = master
|
||||
.get_protocol_features()
|
||||
.map_err(Error::VhostUserGetProtocolFeatures)?;
|
||||
@ -347,10 +290,12 @@ impl Fs {
|
||||
|
||||
slave_req_support = true;
|
||||
}
|
||||
|
||||
// Create virtio device config space.
|
||||
// First by adding the tag.
|
||||
let mut config_space = tag.to_string().into_bytes();
|
||||
config_space.resize(CONFIG_SPACE_SIZE, 0);
|
||||
|
||||
// And then by copying the number of queues.
|
||||
let num_queues_slice = (req_num_queues as u32).to_le_bytes();
|
||||
config_space[CONFIG_SPACE_TAG_SIZE..CONFIG_SPACE_SIZE].copy_from_slice(&num_queues_slice);
|
||||
@ -359,95 +304,13 @@ impl Fs {
|
||||
vu: master,
|
||||
queue_sizes: vec![queue_size; num_queues],
|
||||
avail_features,
|
||||
acked_features: avail_features,
|
||||
acked_features,
|
||||
config_space,
|
||||
kill_evt: None,
|
||||
cache,
|
||||
slave_req_support,
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_vu(
|
||||
&mut self,
|
||||
mem: &GuestMemoryMmap,
|
||||
queues: Vec<Queue>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> Result<Vec<(EventFd, Queue)>> {
|
||||
// Set vhost-user owner.
|
||||
self.vu.set_owner().map_err(Error::VhostUserSetOwner)?;
|
||||
|
||||
let mut regions: Vec<VhostUserMemoryRegionInfo> = Vec::new();
|
||||
|
||||
mem.with_regions_mut(|_, region| {
|
||||
let (mmap_handle, mmap_offset) = match region.file_offset() {
|
||||
Some(fo) => (fo.file().as_raw_fd(), fo.start()),
|
||||
None => return Err(MmapError::NoMemoryRegion),
|
||||
};
|
||||
|
||||
let vu_mem_reg = VhostUserMemoryRegionInfo {
|
||||
guest_phys_addr: region.start_addr().raw_value(),
|
||||
memory_size: region.len() as u64,
|
||||
userspace_addr: region.as_ptr() as u64,
|
||||
mmap_offset,
|
||||
mmap_handle,
|
||||
};
|
||||
|
||||
regions.push(vu_mem_reg);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Error::MemoryRegions)?;
|
||||
|
||||
self.vu
|
||||
.set_mem_table(regions.as_slice())
|
||||
.map_err(Error::VhostUserSetMemTable)?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for (queue_index, queue) in queues.into_iter().enumerate() {
|
||||
self.vu
|
||||
.set_vring_num(queue_index, queue.get_max_size())
|
||||
.map_err(Error::VhostUserSetVringNum)?;
|
||||
|
||||
let vring_config = VringConfigData {
|
||||
queue_max_size: queue.get_max_size(),
|
||||
queue_size: queue.size,
|
||||
flags: 0u32,
|
||||
desc_table_addr: mem
|
||||
.get_host_address(queue.desc_table)
|
||||
.ok_or_else(|| Error::DescriptorTableAddress)?
|
||||
as u64,
|
||||
used_ring_addr: mem
|
||||
.get_host_address(queue.used_ring)
|
||||
.ok_or_else(|| Error::UsedAddress)? as u64,
|
||||
avail_ring_addr: mem
|
||||
.get_host_address(queue.avail_ring)
|
||||
.ok_or_else(|| Error::AvailAddress)? as u64,
|
||||
log_addr: None,
|
||||
};
|
||||
|
||||
self.vu
|
||||
.set_vring_addr(queue_index, &vring_config)
|
||||
.map_err(Error::VhostUserSetVringAddr)?;
|
||||
|
||||
self.vu
|
||||
.set_vring_base(queue_index, 0u16)
|
||||
.map_err(Error::VhostUserSetVringBase)?;
|
||||
|
||||
let vu_call_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::IrqEventCreate)?;
|
||||
|
||||
self.vu
|
||||
.set_vring_call(queue_index, &vu_call_evt)
|
||||
.map_err(Error::VhostUserSetVringCall)?;
|
||||
|
||||
result.push((vu_call_evt, queue));
|
||||
|
||||
self.vu
|
||||
.set_vring_kick(queue_index, &queue_evts[queue_index])
|
||||
.map_err(Error::VhostUserSetVringKick)?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fs {
|
||||
@ -552,8 +415,13 @@ impl VirtioDevice for Fs {
|
||||
};
|
||||
self.kill_evt = Some(self_kill_evt);
|
||||
|
||||
let vu_call_evt_queue_list = self
|
||||
.setup_vu(&mem.read().unwrap(), queues, queue_evts)
|
||||
let vu_call_evt_queue_list = setup_vhost_user(
|
||||
&mut self.vu,
|
||||
&mem.read().unwrap(),
|
||||
queues,
|
||||
queue_evts,
|
||||
self.acked_features,
|
||||
)
|
||||
.map_err(ActivateError::VhostUserSetup)?;
|
||||
|
||||
// Initialize slave communication.
|
||||
|
@ -49,6 +49,8 @@ pub enum Error {
|
||||
VhostUserCreateMaster(VhostError),
|
||||
/// Failed to open vhost device.
|
||||
VhostUserOpen(VhostError),
|
||||
/// Connection to socket failed.
|
||||
VhostUserConnect(vhost_rs::Error),
|
||||
/// Get features failed.
|
||||
VhostUserGetFeatures(VhostError),
|
||||
/// Get protocol features failed.
|
||||
@ -85,6 +87,10 @@ pub enum Error {
|
||||
VhostUserMemoryRegion(MmapError),
|
||||
/// Failed to handle vhost-user slave request.
|
||||
VhostUserSlaveRequest(vhost_rs::vhost_user::Error),
|
||||
/// Failed to create the master request handler from slave.
|
||||
MasterReqHandlerCreation(vhost_rs::vhost_user::Error),
|
||||
/// Set slave request fd failed.
|
||||
VhostUserSetSlaveRequestFd(vhost_rs::Error),
|
||||
/// Invalid used address.
|
||||
UsedAddress,
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ pub enum DeviceManagerError {
|
||||
CreateVirtioRng(io::Error),
|
||||
|
||||
/// Cannot create virtio-fs device
|
||||
CreateVirtioFs(vm_virtio::vhost_user::fs::Error),
|
||||
CreateVirtioFs(vm_virtio::vhost_user::Error),
|
||||
|
||||
/// Cannot create virtio-pmem device
|
||||
CreateVirtioPmem(io::Error),
|
||||
|
Loading…
Reference in New Issue
Block a user