summary refs log tree commit diff
path: root/pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch')
-rw-r--r--pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch492
1 files changed, 492 insertions, 0 deletions
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch b/pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch
new file mode 100644
index 00000000000..e4b7f96c030
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/vhost/0002-vhost_user-add-shared-memory-region-support.patch
@@ -0,0 +1,492 @@
+From e1f7130bfbe529a7fda1a598866e0dea41b6ba74 Mon Sep 17 00:00:00 2001
+From: David Stevens <stevensd@chromium.org>
+Date: Wed, 15 Jun 2022 16:45:12 +0900
+Subject: [PATCH 2/3] 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 <keiichiw@chromium.org>
+Commit-Queue: David Stevens <stevensd@chromium.org>
+Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
+Tested-by: kokoro <noreply+kokoro@google.com>
+(cherry-picked from commit f436e2706011fa5f34dc415972434aa3299ebc43)
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/vhost-user-backend/src/handler.rs      |  10 +-
+ crates/vhost/src/vhost_user/dummy_slave.rs    |   4 +
+ crates/vhost/src/vhost_user/master.rs         |  25 ++++
+ .../src/vhost_user/master_req_handler.rs      |  57 ++++++--
+ crates/vhost/src/vhost_user/message.rs        | 136 +++++++++++++++++-
+ crates/vhost/src/vhost_user/slave_req.rs      |  20 ++-
+ .../vhost/src/vhost_user/slave_req_handler.rs |  15 ++
+ 7 files changed, 247 insertions(+), 20 deletions(-)
+
+diff --git a/crates/vhost-user-backend/src/handler.rs b/crates/vhost-user-backend/src/handler.rs
+index 262bf6c..73402b2 100644
+--- a/crates/vhost-user-backend/src/handler.rs
++++ b/crates/vhost-user-backend/src/handler.rs
+@@ -11,9 +11,9 @@ use std::sync::Arc;
+ use std::thread;
+ 
+ use vhost::vhost_user::message::{
+-    VhostUserConfigFlags, VhostUserMemoryRegion, VhostUserProtocolFeatures,
+-    VhostUserSingleMemoryRegion, VhostUserVirtioFeatures, VhostUserVringAddrFlags,
+-    VhostUserVringState,
++    VhostSharedMemoryRegion, VhostUserConfigFlags, VhostUserMemoryRegion,
++    VhostUserProtocolFeatures, VhostUserSingleMemoryRegion, VhostUserVirtioFeatures,
++    VhostUserVringAddrFlags, VhostUserVringState,
+ };
+ use vhost::vhost_user::{
+     Error as VhostUserError, Result as VhostUserResult, Slave, VhostUserSlaveReqHandlerMut,
+@@ -602,6 +602,10 @@ where
+ 
+         Ok(())
+     }
++
++    fn get_shared_memory_regions(&mut self) -> VhostUserResult<Vec<VhostSharedMemoryRegion>> {
++        Ok(Vec::new())
++    }
+ }
+ 
+ impl<S, V, B: Bitmap> Drop for VhostUserHandler<S, V, B> {
+diff --git a/crates/vhost/src/vhost_user/dummy_slave.rs b/crates/vhost/src/vhost_user/dummy_slave.rs
+index ae728a0..00a1ae8 100644
+--- a/crates/vhost/src/vhost_user/dummy_slave.rs
++++ b/crates/vhost/src/vhost_user/dummy_slave.rs
+@@ -291,4 +291,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
+     fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> {
+         Ok(())
+     }
++
++    fn get_shared_memory_regions(&mut self) -> Result<Vec<VhostSharedMemoryRegion>> {
++        Ok(Vec::new())
++    }
+ }
+diff --git a/crates/vhost/src/vhost_user/master.rs b/crates/vhost/src/vhost_user/master.rs
+index 89aec20..6808cb0 100644
+--- a/crates/vhost/src/vhost_user/master.rs
++++ b/crates/vhost/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<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ fn error_code<T>(err: VhostUserError) -> Result<T> {
+@@ -513,6 +516,28 @@ 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<Vec<VhostSharedMemoryRegion>> {
++        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::<VhostUserU64>(&hdr)?;
++        let struct_size = mem::size_of::<VhostSharedMemoryRegion>();
++        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/crates/vhost/src/vhost_user/master_req_handler.rs b/crates/vhost/src/vhost_user/master_req_handler.rs
+index c9c528b..3d01542 100644
+--- a/crates/vhost/src/vhost_user/master_req_handler.rs
++++ b/crates/vhost/src/vhost_user/master_req_handler.rs
+@@ -33,6 +33,16 @@ pub trait VhostUserMasterReqHandler {
+         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<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
++    /// Handle shared memory region unmapping requests.
++    fn shmem_unmap(&self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        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<u64> {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+@@ -66,6 +76,16 @@ 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<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
++    /// Handle shared memory region unmapping requests.
++    fn shmem_unmap(&mut self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        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<u64> {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+@@ -95,6 +115,14 @@ impl<S: VhostUserMasterReqHandlerMut> VhostUserMasterReqHandler for Mutex<S> {
+         self.lock().unwrap().handle_config_change()
+     }
+ 
++    fn shmem_map(&self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
++        self.lock().unwrap().shmem_map(req, fd)
++    }
++
++    fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        self.lock().unwrap().shmem_unmap(req)
++    }
++
+     fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
+         self.lock().unwrap().fs_slave_map(fs, fd)
+     }
+@@ -222,6 +250,19 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+                     .handle_config_change()
+                     .map_err(Error::ReqHandlerError)
+             }
++            Ok(SlaveReq::SHMEM_MAP) => {
++                let msg = self.extract_msg_body::<VhostUserShmemMapMsg>(&hdr, size, &buf)?;
++                // check_attached_files() has validated files
++                self.backend
++                    .shmem_map(&msg, &files.unwrap()[0])
++                    .map_err(Error::ReqHandlerError)
++            }
++            Ok(SlaveReq::SHMEM_UNMAP) => {
++                let msg = self.extract_msg_body::<VhostUserShmemUnmapMsg>(&hdr, size, &buf)?;
++                self.backend
++                    .shmem_unmap(&msg)
++                    .map_err(Error::ReqHandlerError)
++            }
+             Ok(SlaveReq::FS_MAP) => {
+                 let msg = self.extract_msg_body::<VhostUserFSSlaveMsg>(&hdr, size, &buf)?;
+                 // check_attached_files() has validated files
+@@ -251,7 +292,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+             _ => Err(Error::InvalidMessage),
+         };
+ 
+-        self.send_ack_message(&hdr, &res)?;
++        self.send_reply(&hdr, &res)?;
+ 
+         res
+     }
+@@ -285,7 +326,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+         files: &Option<Vec<File>>,
+     ) -> Result<()> {
+         match hdr.get_code() {
+-            Ok(SlaveReq::FS_MAP | SlaveReq::FS_IO) => {
++            Ok(SlaveReq::SHMEM_MAP | SlaveReq::FS_MAP | SlaveReq::FS_IO) => {
+                 // Expect a single file is passed.
+                 match files {
+                     Some(files) if files.len() == 1 => Ok(()),
+@@ -327,12 +368,12 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+         ))
+     }
+ 
+-    fn send_ack_message(
+-        &mut self,
+-        req: &VhostUserMsgHeader<SlaveReq>,
+-        res: &Result<u64>,
+-    ) -> Result<()> {
+-        if self.reply_ack_negotiated && req.is_need_reply() {
++    fn send_reply(&mut self, req: &VhostUserMsgHeader<SlaveReq>, res: &Result<u64>) -> Result<()> {
++        if matches!(
++            req.get_code(),
++            Ok(SlaveReq::SHMEM_MAP | SlaveReq::SHMEM_UNMAP)
++        ) || (self.reply_ack_negotiated && req.is_need_reply())
++        {
+             let hdr = self.new_reply_header::<VhostUserU64>(req)?;
+             let def_err = libc::EINVAL;
+             let val = match res {
+diff --git a/crates/vhost/src/vhost_user/message.rs b/crates/vhost/src/vhost_user/message.rs
+index bbd8eb9..be24992 100644
+--- a/crates/vhost/src/vhost_user/message.rs
++++ b/crates/vhost/src/vhost_user/message.rs
+@@ -146,8 +146,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<MasterReq> for u32 {
+@@ -178,16 +180,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<SlaveReq> for u32 {
+@@ -972,6 +978,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)]
+@@ -1103,6 +1202,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/crates/vhost/src/vhost_user/slave_req.rs b/crates/vhost/src/vhost_user/slave_req.rs
+index ade1e91..b7ecd20 100644
+--- a/crates/vhost/src/vhost_user/slave_req.rs
++++ b/crates/vhost/src/vhost_user/slave_req.rs
+@@ -46,12 +46,16 @@ impl SlaveInternal {
+         }
+         self.sock.send_message(&hdr, body, fds)?;
+ 
+-        self.wait_for_ack(&hdr)
++        self.wait_for_reply(&hdr)
+     }
+ 
+-    fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
++    fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
+         self.check_state()?;
+-        if !self.reply_ack_negotiated {
++        if !matches!(
++            hdr.get_code(),
++            Ok(SlaveReq::SHMEM_MAP | SlaveReq::SHMEM_UNMAP)
++        ) && !self.reply_ack_negotiated
++        {
+             return Ok(0);
+         }
+ 
+@@ -129,6 +133,16 @@ impl Slave {
+ }
+ 
+ impl VhostUserMasterReqHandler for Slave {
++    /// Handle shared memory region mapping requests.
++    fn shmem_map(&self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
++        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<u64> {
++        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<u64> {
+         self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd.as_raw_fd()]))
+diff --git a/crates/vhost/src/vhost_user/slave_req_handler.rs b/crates/vhost/src/vhost_user/slave_req_handler.rs
+index e998339..b84feca 100644
+--- a/crates/vhost/src/vhost_user/slave_req_handler.rs
++++ b/crates/vhost/src/vhost_user/slave_req_handler.rs
+@@ -70,6 +70,7 @@ pub trait VhostUserSlaveReqHandler {
+     fn get_max_mem_slots(&self) -> Result<u64>;
+     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<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ /// Services provided to the master by the slave without interior mutability.
+@@ -118,6 +119,7 @@ pub trait VhostUserSlaveReqHandlerMut {
+     fn get_max_mem_slots(&mut self) -> Result<u64>;
+     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<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
+@@ -226,6 +228,10 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
+     fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> {
+         self.lock().unwrap().remove_mem_region(region)
+     }
++
++    fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>> {
++        self.lock().unwrap().get_shared_memory_regions()
++    }
+ }
+ 
+ /// Server to handle service requests from masters from the master communication channel.
+@@ -519,6 +525,15 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
+                 let res = self.backend.remove_mem_region(&msg);
+                 self.send_ack_message(&hdr, res)?;
+             }
++            Ok(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);
+             }
+-- 
+2.42.0
+