From b7d3ad906386e092794225803608608fce93495b Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Fri, 30 Aug 2019 10:40:33 -0700 Subject: [PATCH] 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 --- vm-virtio/src/lib.rs | 3 +- vm-virtio/src/vhost_user/fs.rs | 226 +++++++------------------------- vm-virtio/src/vhost_user/mod.rs | 6 + vmm/src/vm.rs | 2 +- 4 files changed, 55 insertions(+), 182 deletions(-) diff --git a/vm-virtio/src/lib.rs b/vm-virtio/src/lib.rs index 4cc5b9d62..676360345 100755 --- a/vm-virtio/src/lib.rs +++ b/vm-virtio/src/lib.rs @@ -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), } diff --git a/vm-virtio/src/vhost_user/fs.rs b/vm-virtio/src/vhost_user/fs.rs index 78771d5b5..3b74d1bb2 100644 --- a/vm-virtio/src/vhost_user/fs.rs +++ b/vm-virtio/src/vhost_user/fs.rs @@ -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 = result::Result; - struct SlaveReqHandler { cache_size: u64, mmap_cache_addr: u64, @@ -185,9 +118,9 @@ struct FsEpollHandler { } impl FsEpollHandler { - 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 FsEpollHandler { 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 FsEpollHandler { 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 FsEpollHandler { 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 FsEpollHandler { // appropriate to retry, by calling into epoll_wait(). continue; } - return Err(DeviceError::EpollWait(e)); + return Err(Error::EpollWait(e)); } }; @@ -259,7 +192,7 @@ impl FsEpollHandler { ) { error!( "Failed to signal used queue: {:?}", - DeviceError::FailedSignalingUsedQueue(e) + Error::FailedSignalingUsedQueue(e) ); break 'epoll; } @@ -272,7 +205,7 @@ impl FsEpollHandler { 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 { 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_evts: Vec, - ) -> Result> { - // Set vhost-user owner. - self.vu.set_owner().map_err(Error::VhostUserSetOwner)?; - - let mut regions: Vec = 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,9 +415,14 @@ 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) - .map_err(ActivateError::VhostUserSetup)?; + 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. let slave_req_handler = if self.slave_req_support { diff --git a/vm-virtio/src/vhost_user/mod.rs b/vm-virtio/src/vhost_user/mod.rs index 72c23b768..6c5271843 100644 --- a/vm-virtio/src/vhost_user/mod.rs +++ b/vm-virtio/src/vhost_user/mod.rs @@ -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, } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index d31fdd727..eb0badd42 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -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),