From 8255d5f7746e18fdae881eb5ab0dabbe9655f5dc Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Fri, 5 Mar 2021 11:05:05 +0100 Subject: [PATCH] vhost_user_backend: Move to latest vhost version The latest vhost version adds the support for the new commands get_max_mem_slots(), add_mem_region() and remove_mem_region(), all related to the new vhost-user protocol feature CONFIGURE_MEM_SLOTS. The vhost_user_backend crate is updated accordingly in order to support these new commands, mostly related to the capability of updating the guest memory mappings with a finer control than set_mem_table() command. Signed-off-by: Sebastien Boeuf --- Cargo.lock | 2 +- fuzz/Cargo.lock | 2 +- vhost_user_backend/src/lib.rs | 111 +++++++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4adb005b8..1e1fffaf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1303,7 +1303,7 @@ dependencies = [ [[package]] name = "vhost" version = "0.1.0" -source = "git+https://github.com/rust-vmm/vhost?branch=master#77843048602ebc69cb5cd0352a66d98a68cb0e7d" +source = "git+https://github.com/rust-vmm/vhost?branch=master#ee3e8722706c984b3dfe12d3a130e92101b78e8f" dependencies = [ "bitflags 1.2.1", "libc", diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 75e6e100f..dfe5684c3 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -692,7 +692,7 @@ dependencies = [ [[package]] name = "vhost" version = "0.1.0" -source = "git+https://github.com/rust-vmm/vhost?branch=master#77843048602ebc69cb5cd0352a66d98a68cb0e7d" +source = "git+https://github.com/rust-vmm/vhost?branch=master#ee3e8722706c984b3dfe12d3a130e92101b78e8f" dependencies = [ "bitflags", "libc", diff --git a/vhost_user_backend/src/lib.rs b/vhost_user_backend/src/lib.rs index 59d7f53e3..b7e8e1478 100644 --- a/vhost_user_backend/src/lib.rs +++ b/vhost_user_backend/src/lib.rs @@ -17,7 +17,8 @@ use std::sync::{Arc, Mutex, RwLock}; use std::thread; use vhost::vhost_user::message::{ VhostUserConfigFlags, VhostUserMemoryRegion, VhostUserProtocolFeatures, - VhostUserVirtioFeatures, VhostUserVringAddrFlags, VhostUserVringState, + VhostUserSingleMemoryRegion, VhostUserVirtioFeatures, VhostUserVringAddrFlags, + VhostUserVringState, }; use vhost::vhost_user::{ Error as VhostUserError, Listener, Result as VhostUserResult, SlaveFsCacheReq, SlaveListener, @@ -25,10 +26,12 @@ use vhost::vhost_user::{ }; use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use vm_memory::guest_memory::FileOffset; -use vm_memory::{GuestAddress, GuestMemoryMmap}; +use vm_memory::{GuestAddress, GuestMemoryMmap, GuestRegionMmap, MmapRegion}; use vm_virtio::Queue; use vmm_sys_util::eventfd::EventFd; +const MAX_MEM_SLOTS: u64 = 32; + #[derive(Debug)] /// Errors related to vhost-user daemon. pub enum Error { @@ -203,10 +206,6 @@ struct AddrMapping { gpa_base: u64, } -struct Memory { - mappings: Vec, -} - pub struct Vring { queue: Queue, kick: Option, @@ -444,7 +443,8 @@ struct VhostUserHandler { num_queues: usize, max_queue_size: usize, queues_per_thread: Vec, - memory: Option, + mappings: Vec, + guest_memory: Option, vrings: Vec>>, worker_threads: Vec>>, } @@ -521,7 +521,8 @@ impl VhostUserHandler { num_queues, max_queue_size, queues_per_thread, - memory: None, + mappings: Vec::new(), + guest_memory: None, vrings, worker_threads, }) @@ -532,11 +533,9 @@ impl VhostUserHandler { } fn vmm_va_to_gpa(&self, vmm_va: u64) -> VhostUserHandlerResult { - if let Some(memory) = &self.memory { - for mapping in memory.mappings.iter() { - if vmm_va >= mapping.vmm_addr && vmm_va < mapping.vmm_addr + mapping.size { - return Ok(vmm_va - mapping.vmm_addr + mapping.gpa_base); - } + for mapping in self.mappings.iter() { + if vmm_va >= mapping.vmm_addr && vmm_va < mapping.vmm_addr + mapping.size { + return Ok(vmm_va - mapping.vmm_addr + mapping.gpa_base); } } @@ -636,11 +635,13 @@ impl VhostUserSlaveReqHandlerMut for VhostUserHandler { self.backend .write() .unwrap() - .update_memory(mem) + .update_memory(mem.clone()) .map_err(|e| { VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) })?; - self.memory = Some(Memory { mappings }); + + self.guest_memory = Some(mem); + self.mappings = mappings; Ok(()) } @@ -670,7 +671,7 @@ impl VhostUserSlaveReqHandlerMut for VhostUserHandler { return Err(VhostUserError::InvalidParam); } - if self.memory.is_some() { + if !self.mappings.is_empty() { let desc_table = self.vmm_va_to_gpa(descriptor).map_err(|e| { VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) })?; @@ -863,6 +864,84 @@ impl VhostUserSlaveReqHandlerMut for VhostUserHandler { fn set_slave_req_fd(&mut self, vu_req: SlaveFsCacheReq) { self.backend.write().unwrap().set_slave_req_fd(vu_req); } + + fn get_max_mem_slots(&mut self) -> VhostUserResult { + Ok(MAX_MEM_SLOTS) + } + + fn add_mem_region( + &mut self, + region: &VhostUserSingleMemoryRegion, + fd: RawFd, + ) -> VhostUserResult<()> { + let file = unsafe { File::from_raw_fd(fd) }; + let mmap_region = MmapRegion::from_file( + FileOffset::new(file, region.mmap_offset), + region.memory_size as usize, + ) + .map_err(|e| VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)))?; + let guest_region = Arc::new( + GuestRegionMmap::new(mmap_region, GuestAddress(region.guest_phys_addr)).map_err( + |e| VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)), + )?, + ); + + let guest_memory = if let Some(guest_memory) = &self.guest_memory { + guest_memory.insert_region(guest_region).map_err(|e| { + VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) + })? + } else { + GuestMemoryMmap::from_arc_regions(vec![guest_region]).map_err(|e| { + VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) + })? + }; + + self.backend + .write() + .unwrap() + .update_memory(guest_memory.clone()) + .map_err(|e| { + VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) + })?; + + self.guest_memory = Some(guest_memory); + + self.mappings.push(AddrMapping { + vmm_addr: region.user_addr, + size: region.memory_size, + gpa_base: region.guest_phys_addr, + }); + + Ok(()) + } + + fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> VhostUserResult<()> { + let guest_memory = if let Some(guest_memory) = &self.guest_memory { + let (updated_guest_memory, _) = guest_memory + .remove_region(GuestAddress(region.guest_phys_addr), region.memory_size) + .map_err(|e| { + VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) + })?; + updated_guest_memory + } else { + return Err(VhostUserError::InvalidOperation); + }; + + self.backend + .write() + .unwrap() + .update_memory(guest_memory.clone()) + .map_err(|e| { + VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)) + })?; + + self.guest_memory = Some(guest_memory); + + self.mappings + .retain(|mapping| mapping.gpa_base != region.guest_phys_addr); + + Ok(()) + } } impl Drop for VhostUserHandler {