diff options
author | Sebastien Boeuf <sebastien.boeuf@intel.com> | 2021-03-04 17:43:35 +0100 |
---|---|---|
committer | Jiang Liu <gerry@linux.alibaba.com> | 2021-03-10 23:37:29 +0800 |
commit | 7e3ab1af4e1c2157e206798683b64eb384c3693a (patch) | |
tree | fb40e5705f62b2374b8dc5d639b60d1792b3a89d | |
parent | e7d46d6980ed1312e16243ff2ec4bb018f9aec5f (diff) | |
download | vmm_vhost-7e3ab1af4e1c2157e206798683b64eb384c3693a.tar.gz |
vhost_user: Add support for ADD_MEM_REG
Adding support for a new message ADD_MEM_REG. This command request a new
region to be added and mapped by the vhost-user backend.
It is designed for supporting memory hotplug, avoiding the limitation
from SET_MEM_TABLE (supports only 8 regions).
It is only available if the protocol feature
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS has been negotiated.
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
-rw-r--r-- | src/vhost_user/dummy_slave.rs | 4 | ||||
-rw-r--r-- | src/vhost_user/master.rs | 24 | ||||
-rw-r--r-- | src/vhost_user/message.rs | 43 | ||||
-rw-r--r-- | src/vhost_user/mod.rs | 15 | ||||
-rw-r--r-- | src/vhost_user/slave_req_handler.rs | 28 |
5 files changed, 114 insertions, 0 deletions
diff --git a/src/vhost_user/dummy_slave.rs b/src/vhost_user/dummy_slave.rs index 989888f..895537b 100644 --- a/src/vhost_user/dummy_slave.rs +++ b/src/vhost_user/dummy_slave.rs @@ -248,4 +248,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler { fn get_max_mem_slots(&mut self) -> Result<u64> { Ok(MAX_MEM_SLOTS as u64) } + + fn add_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion, _fd: RawFd) -> Result<()> { + Ok(()) + } } diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs index a721355..d27e4fb 100644 --- a/src/vhost_user/master.rs +++ b/src/vhost_user/master.rs @@ -53,6 +53,9 @@ pub trait VhostUserMaster: VhostBackend { /// Query the maximum amount of memory slots supported by the backend. fn get_max_mem_slots(&mut self) -> Result<u64>; + + /// Add a new guest memory mapping for vhost to use. + fn add_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>; } fn error_code<T>(err: VhostUserError) -> Result<T> { @@ -451,6 +454,27 @@ impl VhostUserMaster for Master { Ok(val.value) } + + fn add_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()> { + let mut node = self.node(); + if node.acked_protocol_features & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() == 0 + { + return error_code(VhostUserError::InvalidOperation); + } + if region.memory_size == 0 || region.mmap_handle < 0 { + return error_code(VhostUserError::InvalidParam); + } + + let body = VhostUserSingleMemoryRegion::new( + region.guest_phys_addr, + region.memory_size, + region.userspace_addr, + region.mmap_offset, + ); + let fds = [region.mmap_handle]; + let hdr = node.send_request_with_body(MasterReq::ADD_MEM_REG, &body, Some(&fds))?; + node.wait_for_ack(&hdr).map_err(|e| e.into()) + } } impl AsRawFd for Master { diff --git a/src/vhost_user/message.rs b/src/vhost_user/message.rs index 01e2c2c..ea2df4e 100644 --- a/src/vhost_user/message.rs +++ b/src/vhost_user/message.rs @@ -479,6 +479,49 @@ impl VhostUserMsgValidator for VhostUserMemoryRegion { /// Payload of the VhostUserMemory message. pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>; +/// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG +/// requests. +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct VhostUserSingleMemoryRegion { + /// Padding for correct alignment + padding: u64, + /// Guest physical address of the memory region. + pub guest_phys_addr: u64, + /// Size of the memory region. + pub memory_size: u64, + /// Virtual address in the current process. + pub user_addr: u64, + /// Offset where region starts in the mapped memory. + pub mmap_offset: u64, +} + +impl VhostUserSingleMemoryRegion { + /// Create a new instance. + pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { + VhostUserSingleMemoryRegion { + padding: 0, + guest_phys_addr, + memory_size, + user_addr, + mmap_offset, + } + } +} + +impl VhostUserMsgValidator for VhostUserSingleMemoryRegion { + fn is_valid(&self) -> bool { + if self.memory_size == 0 + || self.guest_phys_addr.checked_add(self.memory_size).is_none() + || self.user_addr.checked_add(self.memory_size).is_none() + || self.mmap_offset.checked_add(self.memory_size).is_none() + { + return false; + } + true + } +} + /// Vring state descriptor. #[repr(packed)] #[derive(Default)] diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs index 38b94ec..3158436 100644 --- a/src/vhost_user/mod.rs +++ b/src/vhost_user/mod.rs @@ -180,11 +180,13 @@ mod dummy_slave; #[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))] mod tests { + use std::fs::File; use std::os::unix::io::AsRawFd; use std::path::{Path, PathBuf}; use std::sync::{Arc, Barrier, Mutex}; use std::thread; use vmm_sys_util::rand::rand_alphanumerics; + use vmm_sys_util::tempfile::TempFile; use super::dummy_slave::{DummySlaveReqHandler, VIRTIO_FEATURES}; use super::message::*; @@ -336,6 +338,9 @@ mod tests { // get_max_mem_slots() slave.handle_request().unwrap(); + // add_mem_region() + slave.handle_request().unwrap(); + sbar.wait(); }); @@ -401,6 +406,16 @@ mod tests { let max_mem_slots = master.get_max_mem_slots().unwrap(); assert_eq!(max_mem_slots, 32); + let region_file: File = TempFile::new().unwrap().into_file(); + let region = VhostUserMemoryRegionInfo { + guest_phys_addr: 0x10_0000, + memory_size: 0x10_0000, + userspace_addr: 0, + mmap_offset: 0, + mmap_handle: region_file.as_raw_fd(), + }; + master.add_mem_region(®ion).unwrap(); + mbar.wait(); } diff --git a/src/vhost_user/slave_req_handler.rs b/src/vhost_user/slave_req_handler.rs index 870d324..3d8d6d5 100644 --- a/src/vhost_user/slave_req_handler.rs +++ b/src/vhost_user/slave_req_handler.rs @@ -63,6 +63,7 @@ pub trait VhostUserSlaveReqHandler { fn set_config(&self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; fn set_slave_req_fd(&self, _vu_req: SlaveFsCacheReq) {} fn get_max_mem_slots(&self) -> Result<u64>; + fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()>; } /// Services provided to the master by the slave without interior mutability. @@ -104,6 +105,7 @@ pub trait VhostUserSlaveReqHandlerMut { fn set_config(&mut self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {} fn get_max_mem_slots(&mut self) -> Result<u64>; + fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()>; } impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> { @@ -196,6 +198,10 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> { fn get_max_mem_slots(&self) -> Result<u64> { self.lock().unwrap().get_max_mem_slots() } + + fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()> { + self.lock().unwrap().add_mem_region(region, fd) + } } /// Server to handle service requests from masters from the master communication channel. @@ -435,6 +441,27 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> { let msg = VhostUserU64::new(num); self.send_reply_message(&hdr, &msg)?; } + MasterReq::ADD_MEM_REG => { + if self.acked_protocol_features + & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() + == 0 + { + return Err(Error::InvalidOperation); + } + let fd = if let Some(fds) = &rfds { + if fds.len() != 1 { + return Err(Error::InvalidParam); + } + fds[0] + } else { + return Err(Error::InvalidParam); + }; + + let msg = + self.extract_request_body::<VhostUserSingleMemoryRegion>(&hdr, size, &buf)?; + let res = self.backend.add_mem_region(&msg, fd); + self.send_ack_message(&hdr, res)?; + } _ => { return Err(Error::InvalidMessage); } @@ -655,6 +682,7 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> { MasterReq::SET_LOG_FD => Ok(rfds), MasterReq::SET_SLAVE_REQ_FD => Ok(rfds), MasterReq::SET_INFLIGHT_FD => Ok(rfds), + MasterReq::ADD_MEM_REG => Ok(rfds), _ => { if rfds.is_some() { Endpoint::<MasterReq>::close_rfds(rfds); |