From b72b87aed5542df7d912750f9745f9854c9cf482 Mon Sep 17 00:00:00 2001 From: David Stevens Date: Wed, 15 Jun 2022 16:45:12 +0900 Subject: [PATCH] vhost_user: add shared memory region support Add support for shared memory regions to vhost-user. This is adding support for a front-end message to query for necessary shared memory regions plus back-end message to support mapping/unmapping files from the shared memory region. go/vvu-shared-memory BUG=b:201745804 TEST=compiles Change-Id: I35c5d260ee09175b68f6778b81883e0070ee0265 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3716344 Reviewed-by: Keiichi Watanabe Commit-Queue: David Stevens Reviewed-by: Alexandre Courbot Tested-by: kokoro (cherry-picked from commit f436e2706011fa5f34dc415972434aa3299ebc43) Signed-off-by: Alyssa Ross --- src/vhost_user/dummy_slave.rs | 4 + src/vhost_user/master.rs | 24 +++++ src/vhost_user/master_req_handler.rs | 78 ++++++++++++--- src/vhost_user/message.rs | 140 +++++++++++++++++++++++++-- src/vhost_user/mod.rs | 2 +- src/vhost_user/slave_fs_cache.rs | 67 ++++++++----- src/vhost_user/slave_req_handler.rs | 27 +++++- 7 files changed, 292 insertions(+), 50 deletions(-) diff --git a/src/vhost_user/dummy_slave.rs b/src/vhost_user/dummy_slave.rs index 222a5bb3..5389e3fb 100644 --- a/src/vhost_user/dummy_slave.rs +++ b/src/vhost_user/dummy_slave.rs @@ -271,4 +271,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler { fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> { Ok(()) } + + fn get_shared_memory_regions(&mut self) -> Result> { + Ok(Vec::new()) + } } diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs index 711b6739..1ad47aaa 100644 --- a/src/vhost_user/master.rs +++ b/src/vhost_user/master.rs @@ -72,6 +72,9 @@ pub trait VhostUserMaster: VhostBackend { /// Remove a guest memory mapping from vhost. fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>; + + /// Gets the shared memory regions used by the device. + fn get_shared_memory_regions(&self) -> Result>; } fn error_code(err: VhostUserError) -> Result { @@ -552,6 +555,27 @@ impl VhostUserMaster for Master { let hdr = node.send_request_with_body(MasterReq::REM_MEM_REG, &body, None)?; node.wait_for_ack(&hdr).map_err(|e| e.into()) } + + fn get_shared_memory_regions(&self) -> Result> { + let mut node = self.node(); + let hdr = node.send_request_header(MasterReq::GET_SHARED_MEMORY_REGIONS, None)?; + let (body_reply, buf_reply, rfds) = node.recv_reply_with_payload::(&hdr)?; + let struct_size = mem::size_of::(); + if rfds.is_some() || buf_reply.len() != body_reply.value as usize * struct_size { + return error_code(VhostUserError::InvalidMessage); + } + let mut regions = Vec::new(); + let mut offset = 0; + for _ in 0..body_reply.value { + regions.push( + // Can't fail because the input is the correct size. + VhostSharedMemoryRegion::from_slice(&buf_reply[offset..(offset + struct_size)]) + .unwrap().clone(), + ); + offset += struct_size; + } + Ok(regions) + } } impl AsRawFd for Master { diff --git a/src/vhost_user/master_req_handler.rs b/src/vhost_user/master_req_handler.rs index 0ecda4e3..d0d6529b 100644 --- a/src/vhost_user/master_req_handler.rs +++ b/src/vhost_user/master_req_handler.rs @@ -17,7 +17,7 @@ use super::{Error, HandlerResult, Result}; /// request services from masters. The [VhostUserMasterReqHandler] trait defines services provided /// by masters, and it's used both on the master side and slave side. /// - on the slave side, a stub forwarder implementing [VhostUserMasterReqHandler] will proxy -/// service requests to masters. The [SlaveFsCacheReq] is an example stub forwarder. +/// service requests to masters. The [Slave] is an example stub forwarder. /// - on the master side, the [MasterReqHandler] will forward service requests to a handler /// implementing [VhostUserMasterReqHandler]. /// @@ -26,13 +26,27 @@ use super::{Error, HandlerResult, Result}; /// /// [VhostUserMasterReqHandler]: trait.VhostUserMasterReqHandler.html /// [MasterReqHandler]: struct.MasterReqHandler.html -/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html +/// [Slave]: struct.Slave.html pub trait VhostUserMasterReqHandler { /// Handle device configuration change notifications. fn handle_config_change(&self) -> HandlerResult { Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) } + /// Handle shared memory region mapping requests. + fn shmem_map( + &self, + _req: &VhostUserShmemMapMsg, + _fd: &dyn AsRawFd, + ) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + + /// Handle shared memory region unmapping requests. + fn shmem_unmap(&self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + /// Handle virtio-fs map file requests. fn fs_slave_map(&self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult { Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) @@ -66,6 +80,20 @@ pub trait VhostUserMasterReqHandlerMut { Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) } + /// Handle shared memory region mapping requests. + fn shmem_map( + &mut self, + _req: &VhostUserShmemMapMsg, + _fd: &dyn AsRawFd, + ) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + + /// Handle shared memory region unmapping requests. + fn shmem_unmap(&mut self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + /// Handle virtio-fs map file requests. fn fs_slave_map(&mut self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult { Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) @@ -95,6 +123,18 @@ impl VhostUserMasterReqHandler for Mutex { self.lock().unwrap().handle_config_change() } + fn shmem_map( + &self, + req: &VhostUserShmemMapMsg, + fd: &dyn AsRawFd, + ) -> HandlerResult { + self.lock().unwrap().shmem_map(req, fd) + } + + fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult { + self.lock().unwrap().shmem_unmap(req) + } + fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult { self.lock().unwrap().fs_slave_map(fs, fd) } @@ -222,6 +262,19 @@ impl MasterReqHandler { .handle_config_change() .map_err(Error::ReqHandlerError) } + SlaveReq::SHMEM_MAP => { + let msg = self.extract_msg_body::(&hdr, size, &buf)?; + // check_attached_files() has validated files + self.backend + .shmem_map(&msg, &files.unwrap()[0]) + .map_err(Error::ReqHandlerError) + } + SlaveReq::SHMEM_UNMAP => { + let msg = self.extract_msg_body::(&hdr, size, &buf)?; + self.backend + .shmem_unmap(&msg) + .map_err(Error::ReqHandlerError) + } SlaveReq::FS_MAP => { let msg = self.extract_msg_body::(&hdr, size, &buf)?; // check_attached_files() has validated files @@ -251,7 +304,7 @@ impl MasterReqHandler { _ => Err(Error::InvalidMessage), }; - self.send_ack_message(&hdr, &res)?; + self.send_reply(&hdr, &res)?; res } @@ -285,7 +338,7 @@ impl MasterReqHandler { files: &Option>, ) -> Result<()> { match hdr.get_code() { - SlaveReq::FS_MAP | SlaveReq::FS_IO => { + SlaveReq::SHMEM_MAP | SlaveReq::FS_MAP | SlaveReq::FS_IO => { // Expect a single file is passed. match files { Some(files) if files.len() == 1 => Ok(()), @@ -326,12 +379,11 @@ impl MasterReqHandler { )) } - fn send_ack_message( - &mut self, - req: &VhostUserMsgHeader, - res: &Result, - ) -> Result<()> { - if self.reply_ack_negotiated && req.is_need_reply() { + fn send_reply(&mut self, req: &VhostUserMsgHeader, res: &Result) -> Result<()> { + if req.get_code() == SlaveReq::SHMEM_MAP + || req.get_code() == SlaveReq::SHMEM_UNMAP + || (self.reply_ack_negotiated && req.is_need_reply()) + { let hdr = self.new_reply_header::(req)?; let def_err = libc::EINVAL; let val = match res { @@ -362,7 +414,7 @@ mod tests { use super::*; #[cfg(feature = "vhost-user-slave")] - use crate::vhost_user::SlaveFsCacheReq; + use crate::vhost_user::Slave; #[cfg(feature = "vhost-user-slave")] use std::os::unix::io::FromRawFd; @@ -410,7 +462,7 @@ mod tests { panic!("failed to duplicated tx fd!"); } let stream = unsafe { UnixStream::from_raw_fd(fd) }; - let fs_cache = SlaveFsCacheReq::from_stream(stream); + let fs_cache = Slave::from_stream(stream); std::thread::spawn(move || { let res = handler.handle_request().unwrap(); @@ -440,7 +492,7 @@ mod tests { panic!("failed to duplicated tx fd!"); } let stream = unsafe { UnixStream::from_raw_fd(fd) }; - let fs_cache = SlaveFsCacheReq::from_stream(stream); + let fs_cache = Slave::from_stream(stream); std::thread::spawn(move || { let res = handler.handle_request().unwrap(); diff --git a/src/vhost_user/message.rs b/src/vhost_user/message.rs index d61c17a1..66139972 100644 --- a/src/vhost_user/message.rs +++ b/src/vhost_user/message.rs @@ -139,8 +139,10 @@ pub enum MasterReq { /// Query the backend for its device status as defined in the VIRTIO /// specification. GET_STATUS = 40, + /// Get a list of the device's shared memory regions. + GET_SHARED_MEMORY_REGIONS = 41, /// Upper bound of valid commands. - MAX_CMD = 41, + MAX_CMD = 42, } impl From for u32 { @@ -171,16 +173,20 @@ pub enum SlaveReq { VRING_CALL = 4, /// Indicate that an error occurred on the specific vring. VRING_ERR = 5, + /// Indicates a request to map a fd into a shared memory region. + SHMEM_MAP = 6, + /// Indicates a request to unmap part of a shared memory region. + SHMEM_UNMAP = 7, /// Virtio-fs draft: map file content into the window. - FS_MAP = 6, + FS_MAP = 8, /// Virtio-fs draft: unmap file content from the window. - FS_UNMAP = 7, + FS_UNMAP = 9, /// Virtio-fs draft: sync file content. - FS_SYNC = 8, + FS_SYNC = 10, /// Virtio-fs draft: perform a read/write from an fd directly to GPA. - FS_IO = 9, + FS_IO = 11, /// Upper bound of valid commands. - MAX_CMD = 10, + MAX_CMD = 12, } impl From for u32 { @@ -817,7 +823,7 @@ pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8; /// Slave request message to update the MMIO window. #[repr(packed)] -#[derive(Default)] +#[derive(Clone, Copy, Default)] pub struct VhostUserFSSlaveMsg { /// File offset. pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], @@ -828,6 +834,8 @@ pub struct VhostUserFSSlaveMsg { /// Flags for the mmap operation pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES], } +// Safe because it only has data and has no implicit padding. +unsafe impl ByteValued for VhostUserFSSlaveMsg {} impl VhostUserMsgValidator for VhostUserFSSlaveMsg { fn is_valid(&self) -> bool { @@ -843,6 +851,99 @@ impl VhostUserMsgValidator for VhostUserFSSlaveMsg { } } +bitflags! { + #[derive(Default)] + /// Flags for SHMEM_MAP messages. + pub struct VhostUserShmemMapMsgFlags: u8 { + /// Empty permission. + const EMPTY = 0x0; + /// Read permission. + const MAP_R = 0x1; + /// Write permission. + const MAP_W = 0x2; + } +} + +/// Slave request message to map a file into a shared memory region. +#[repr(C, packed)] +#[derive(Default, Copy, Clone)] +pub struct VhostUserShmemMapMsg { + /// Flags for the mmap operation + pub flags: VhostUserShmemMapMsgFlags, + /// Shared memory region id. + pub shmid: u8, + padding: [u8; 6], + /// Offset into the shared memory region. + pub shm_offset: u64, + /// File offset. + pub fd_offset: u64, + /// Size of region to map. + pub len: u64, +} +// Safe because it only has data and has no implicit padding. +unsafe impl ByteValued for VhostUserShmemMapMsg {} + +impl VhostUserMsgValidator for VhostUserShmemMapMsg { + fn is_valid(&self) -> bool { + (self.flags.bits() & !VhostUserFSSlaveMsgFlags::all().bits() as u8) == 0 + && self.fd_offset.checked_add(self.len).is_some() + && self.shm_offset.checked_add(self.len).is_some() + } +} + +impl VhostUserShmemMapMsg { + /// New instance of VhostUserShmemMapMsg struct + pub fn new( + shmid: u8, + shm_offset: u64, + fd_offset: u64, + len: u64, + flags: VhostUserShmemMapMsgFlags, + ) -> Self { + Self { + flags, + shmid, + padding: [0; 6], + shm_offset, + fd_offset, + len, + } + } +} + +/// Slave request message to unmap part of a shared memory region. +#[repr(C, packed)] +#[derive(Default, Copy, Clone)] +pub struct VhostUserShmemUnmapMsg { + /// Shared memory region id. + pub shmid: u8, + padding: [u8; 7], + /// Offset into the shared memory region. + pub shm_offset: u64, + /// Size of region to unmap. + pub len: u64, +} +// Safe because it only has data and has no implicit padding. +unsafe impl ByteValued for VhostUserShmemUnmapMsg {} + +impl VhostUserMsgValidator for VhostUserShmemUnmapMsg { + fn is_valid(&self) -> bool { + self.shm_offset.checked_add(self.len).is_some() + } +} + +impl VhostUserShmemUnmapMsg { + /// New instance of VhostUserShmemUnmapMsg struct + pub fn new(shmid: u8, shm_offset: u64, len: u64) -> Self { + Self { + shmid, + padding: [0; 7], + shm_offset, + len, + } + } +} + /// Inflight I/O descriptor state for split virtqueues #[repr(packed)] #[derive(Clone, Copy, Default)] @@ -974,6 +1075,31 @@ impl QueueRegionPacked { } } +/// Virtio shared memory descriptor. +#[repr(packed)] +#[derive(Default, Copy, Clone)] +pub struct VhostSharedMemoryRegion { + /// The shared memory region's shmid. + pub id: u8, + /// Padding + padding: [u8; 7], + /// The length of the shared memory region. + pub length: u64, +} +// Safe because it only has data and has no implicit padding. +unsafe impl ByteValued for VhostSharedMemoryRegion {} + +impl VhostSharedMemoryRegion { + /// New instance of VhostSharedMemoryRegion struct + pub fn new(id: u8, length: u64) -> Self { + VhostSharedMemoryRegion { + id, + padding: [0; 7], + length, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs index 6b1afb8c..a2f0af88 100644 --- a/src/vhost_user/mod.rs +++ b/src/vhost_user/mod.rs @@ -50,7 +50,7 @@ pub use self::slave_req_handler::{ #[cfg(feature = "vhost-user-slave")] mod slave_fs_cache; #[cfg(feature = "vhost-user-slave")] -pub use self::slave_fs_cache::SlaveFsCacheReq; +pub use self::slave_fs_cache::Slave; /// Errors for vhost-user operations #[derive(Debug)] diff --git a/src/vhost_user/slave_fs_cache.rs b/src/vhost_user/slave_fs_cache.rs index e9ad7cf6..369d682a 100644 --- a/src/vhost_user/slave_fs_cache.rs +++ b/src/vhost_user/slave_fs_cache.rs @@ -7,11 +7,13 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::sync::{Arc, Mutex, MutexGuard}; +use vm_memory::ByteValued; + use super::connection::Endpoint; use super::message::*; use super::{Error, HandlerResult, Result, VhostUserMasterReqHandler}; -struct SlaveFsCacheReqInternal { +struct SlaveInternal { sock: Endpoint, // Protocol feature VHOST_USER_PROTOCOL_F_REPLY_ACK has been negotiated. @@ -21,7 +23,7 @@ struct SlaveFsCacheReqInternal { error: Option, } -impl SlaveFsCacheReqInternal { +impl SlaveInternal { fn check_state(&self) -> Result { match self.error { Some(e) => Err(Error::SocketBroken(std::io::Error::from_raw_os_error(e))), @@ -29,27 +31,30 @@ impl SlaveFsCacheReqInternal { } } - fn send_message( + fn send_message( &mut self, request: SlaveReq, - fs: &VhostUserFSSlaveMsg, + msg: &T, fds: Option<&[RawFd]>, ) -> Result { self.check_state()?; - let len = mem::size_of::(); + let len = mem::size_of::(); let mut hdr = VhostUserMsgHeader::new(request, 0, len as u32); if self.reply_ack_negotiated { hdr.set_need_reply(true); } - self.sock.send_message(&hdr, fs, fds)?; + self.sock.send_message(&hdr, msg, fds)?; - self.wait_for_ack(&hdr) + self.wait_for_reply(&hdr) } - fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader) -> Result { + fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader) -> Result { self.check_state()?; - if !self.reply_ack_negotiated { + if hdr.get_code() != SlaveReq::SHMEM_MAP + && hdr.get_code() != SlaveReq::SHMEM_UNMAP + && !self.reply_ack_negotiated + { return Ok(0); } @@ -68,22 +73,22 @@ impl SlaveFsCacheReqInternal { /// Request proxy to send vhost-user-fs slave requests to the master through the slave /// communication channel. /// -/// The [SlaveFsCacheReq] acts as a message proxy to forward vhost-user-fs slave requests to the +/// The [Slave] acts as a message proxy to forward vhost-user-fs slave requests to the /// master through the vhost-user slave communication channel. The forwarded messages will be /// handled by the [MasterReqHandler] server. /// -/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html +/// [Slave]: struct.Slave.html /// [MasterReqHandler]: struct.MasterReqHandler.html #[derive(Clone)] -pub struct SlaveFsCacheReq { +pub struct Slave { // underlying Unix domain socket for communication - node: Arc>, + node: Arc>, } -impl SlaveFsCacheReq { +impl Slave { fn new(ep: Endpoint) -> Self { - SlaveFsCacheReq { - node: Arc::new(Mutex::new(SlaveFsCacheReqInternal { + Slave { + node: Arc::new(Mutex::new(SlaveInternal { sock: ep, reply_ack_negotiated: false, error: None, @@ -91,18 +96,18 @@ impl SlaveFsCacheReq { } } - fn node(&self) -> MutexGuard { + fn node(&self) -> MutexGuard { self.node.lock().unwrap() } - fn send_message( + fn send_message( &self, request: SlaveReq, - fs: &VhostUserFSSlaveMsg, + msg: &T, fds: Option<&[RawFd]>, ) -> io::Result { self.node() - .send_message(request, fs, fds) + .send_message(request, msg, fds) .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e))) } @@ -126,7 +131,21 @@ impl SlaveFsCacheReq { } } -impl VhostUserMasterReqHandler for SlaveFsCacheReq { +impl VhostUserMasterReqHandler for Slave { + /// Handle shared memory region mapping requests. + fn shmem_map( + &self, + req: &VhostUserShmemMapMsg, + fd: &dyn AsRawFd, + ) -> HandlerResult { + self.send_message(SlaveReq::SHMEM_MAP, req, Some(&[fd.as_raw_fd()])) + } + + /// Handle shared memory region unmapping requests. + fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult { + self.send_message(SlaveReq::SHMEM_UNMAP, req, None) + } + /// Forward vhost-user-fs map file requests to the slave. fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult { self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd.as_raw_fd()])) @@ -147,7 +166,7 @@ mod tests { #[test] fn test_slave_fs_cache_req_set_failed() { let (p1, _p2) = UnixStream::pair().unwrap(); - let fs_cache = SlaveFsCacheReq::from_stream(p1); + let fs_cache = Slave::from_stream(p1); assert!(fs_cache.node().error.is_none()); fs_cache.set_failed(libc::EAGAIN); @@ -157,7 +176,7 @@ mod tests { #[test] fn test_slave_fs_cache_send_failure() { let (p1, p2) = UnixStream::pair().unwrap(); - let fs_cache = SlaveFsCacheReq::from_stream(p1); + let fs_cache = Slave::from_stream(p1); fs_cache.set_failed(libc::ECONNRESET); fs_cache @@ -172,7 +191,7 @@ mod tests { #[test] fn test_slave_fs_cache_recv_negative() { let (p1, p2) = UnixStream::pair().unwrap(); - let fs_cache = SlaveFsCacheReq::from_stream(p1); + let fs_cache = Slave::from_stream(p1); let mut master = Endpoint::::from_stream(p2); let len = mem::size_of::(); diff --git a/src/vhost_user/slave_req_handler.rs b/src/vhost_user/slave_req_handler.rs index f43159ad..ee313ffd 100644 --- a/src/vhost_user/slave_req_handler.rs +++ b/src/vhost_user/slave_req_handler.rs @@ -8,9 +8,11 @@ use std::os::unix::net::UnixStream; use std::slice; use std::sync::{Arc, Mutex}; +use vm_memory::ByteValued; + use super::connection::Endpoint; use super::message::*; -use super::slave_fs_cache::SlaveFsCacheReq; +use super::slave_fs_cache::Slave; use super::{take_single_file, Error, Result}; /// Services provided to the master by the slave with interior mutability. @@ -62,12 +64,13 @@ pub trait VhostUserSlaveReqHandler { fn set_vring_enable(&self, index: u32, enable: bool) -> Result<()>; fn get_config(&self, offset: u32, size: u32, flags: VhostUserConfigFlags) -> Result>; fn set_config(&self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; - fn set_slave_req_fd(&self, _vu_req: SlaveFsCacheReq) {} + fn set_slave_req_fd(&self, _vu_req: Slave) {} fn get_inflight_fd(&self, inflight: &VhostUserInflight) -> Result<(VhostUserInflight, File)>; fn set_inflight_fd(&self, inflight: &VhostUserInflight, file: File) -> Result<()>; fn get_max_mem_slots(&self) -> Result; fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>; fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>; + fn get_shared_memory_regions(&self) -> Result>; } /// Services provided to the master by the slave without interior mutability. @@ -107,7 +110,7 @@ pub trait VhostUserSlaveReqHandlerMut { flags: VhostUserConfigFlags, ) -> Result>; fn set_config(&mut self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; - fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {} + fn set_slave_req_fd(&mut self, _vu_req: Slave) {} fn get_inflight_fd( &mut self, inflight: &VhostUserInflight, @@ -116,6 +119,7 @@ pub trait VhostUserSlaveReqHandlerMut { fn get_max_mem_slots(&mut self) -> Result; fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>; fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>; + fn get_shared_memory_regions(&mut self) -> Result>; } impl VhostUserSlaveReqHandler for Mutex { @@ -201,7 +205,7 @@ impl VhostUserSlaveReqHandler for Mutex { self.lock().unwrap().set_config(offset, buf, flags) } - fn set_slave_req_fd(&self, vu_req: SlaveFsCacheReq) { + fn set_slave_req_fd(&self, vu_req: Slave) { self.lock().unwrap().set_slave_req_fd(vu_req) } @@ -224,6 +228,10 @@ impl VhostUserSlaveReqHandler for Mutex { fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> { self.lock().unwrap().remove_mem_region(region) } + + fn get_shared_memory_regions(&self) -> Result> { + self.lock().unwrap().get_shared_memory_regions() + } } /// Server to handle service requests from masters from the master communication channel. @@ -528,6 +536,15 @@ impl SlaveReqHandler { let res = self.backend.remove_mem_region(&msg); self.send_ack_message(&hdr, res)?; } + MasterReq::GET_SHARED_MEMORY_REGIONS => { + let regions = self.backend.get_shared_memory_regions()?; + let mut buf = Vec::new(); + let msg = VhostUserU64::new(regions.len() as u64); + for r in regions { + buf.extend_from_slice(r.as_slice()) + } + self.send_reply_with_payload(&hdr, &msg, buf.as_slice())?; + } _ => { return Err(Error::InvalidMessage); } @@ -641,7 +658,7 @@ impl SlaveReqHandler { fn set_slave_req_fd(&mut self, files: Option>) -> Result<()> { let file = take_single_file(files).ok_or(Error::InvalidMessage)?; let sock = unsafe { UnixStream::from_raw_fd(file.into_raw_fd()) }; - let vu_req = SlaveFsCacheReq::from_stream(sock); + let vu_req = Slave::from_stream(sock); self.backend.set_slave_req_fd(vu_req); Ok(()) } -- 2.37.1