diff options
author | Jingkui Wang <jkwang@google.com> | 2018-10-03 13:04:47 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-11-19 16:28:35 -0800 |
commit | e13b180f74ad6d0b1cb1db2a198e294da97e526c (patch) | |
tree | 438e0623a7ec0b0583087da9a5214e6008fad2d9 /vm_control/src | |
parent | b23c091c8bfd37cab8be15c0912d684187969c63 (diff) | |
download | crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar.gz crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar.bz2 crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar.lz crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar.xz crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.tar.zst crosvm-e13b180f74ad6d0b1cb1db2a198e294da97e526c.zip |
crosvm: use msg_socket in vm_control
Refactor existing code to use msg_socket. BUG=None TEST=local build and run Change-Id: Iee72326b330e035303f679e1aedd6e5d18ad4f8a Reviewed-on: https://chromium-review.googlesource.com/1260260 Commit-Ready: Jingkui Wang <jkwang@google.com> Tested-by: Jingkui Wang <jkwang@google.com> Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'vm_control/src')
-rw-r--r-- | vm_control/src/lib.rs | 530 |
1 files changed, 27 insertions, 503 deletions
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index 4d1d036..deec07d 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -11,45 +11,24 @@ //! if the request type expects one. extern crate byteorder; -extern crate data_model; extern crate kvm; extern crate libc; +extern crate msg_socket; extern crate resources; extern crate sys_util; use std::fs::File; use std::io::{Seek, SeekFrom}; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::UnixDatagram; -use std::result; -use libc::{EINVAL, ENODEV, ERANGE}; +use libc::{EINVAL, ENODEV}; use byteorder::{LittleEndian, WriteBytesExt}; -use data_model::{DataInit, Le32, Le64, VolatileMemory}; use kvm::{Datamatch, IoeventAddress, Vm}; -use resources::{GpuMemoryDesc, GpuMemoryPlaneDesc, SystemAllocator}; -use sys_util::{ - Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result, ScmSocket, -}; - -#[derive(Debug, PartialEq)] -/// An error during a request or response transaction. -pub enum VmControlError { - /// Error while sending a request or response. - Send(SysError), - /// Error while receiving a request or response. - Recv(SysError), - /// The type of a received request or response is unknown. - InvalidType, - /// There was not the expected amount of data when receiving a request or response. The inner - /// value is how much data was read. - BadSize(usize), - /// There was no associated file descriptor received for a request that expected it. - ExpectFd, -} - -pub type VmControlResult<T> = result::Result<T, VmControlError>; +use msg_socket::{MsgOnSocket, MsgResult}; +use resources::{GpuMemoryDesc, SystemAllocator}; +use sys_util::{Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result}; /// A file descriptor either borrowed or owned by this. pub enum MaybeOwnedFd { @@ -68,9 +47,29 @@ impl AsRawFd for MaybeOwnedFd { } } +// When sent, it could be owned or borrowed. On the receiver end, it always owned. +impl MsgOnSocket for MaybeOwnedFd { + fn msg_size() -> usize { + 0usize + } + fn max_fd_count() -> usize { + 1usize + } + unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> { + let (fd, size) = RawFd::read_from_buffer(buffer, fds)?; + let file = File::from_raw_fd(fd); + Ok((MaybeOwnedFd::Owned(file), size)) + } + fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> { + let fd = self.as_raw_fd(); + fd.write_to_buffer(buffer, fds) + } +} + /// A request to the main process to perform some operation on the VM. /// /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success. +#[derive(MsgOnSocket)] pub enum VmRequest { /// Try to grow or shrink the VM's balloon. BalloonAdjust(i32), @@ -94,28 +93,6 @@ pub enum VmRequest { }, } -const VM_REQUEST_TYPE_EXIT: u32 = 1; -const VM_REQUEST_TYPE_REGISTER_MEMORY: u32 = 2; -const VM_REQUEST_TYPE_UNREGISTER_MEMORY: u32 = 3; -const VM_REQUEST_TYPE_BALLOON_ADJUST: u32 = 4; -const VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY: u32 = 5; -const VM_REQUEST_SIZE: usize = 32; - -#[repr(C)] -#[derive(Clone, Copy, Default)] -struct VmRequestStruct { - type_: Le32, - slot: Le32, - size: Le64, - num_pages: Le32, - width: Le32, - height: Le32, - format: Le32, -} - -// Safe because it only has data and has no implicit padding. -unsafe impl DataInit for VmRequestStruct {} - fn register_memory( vm: &mut Vm, allocator: &mut SystemAllocator, @@ -140,90 +117,6 @@ fn register_memory( } impl VmRequest { - /// Receive a `VmRequest` from the given socket. - /// - /// A `VmResponse` should be sent out over the given socket before another request is received. - pub fn recv(s: &UnixDatagram) -> VmControlResult<VmRequest> { - assert_eq!(VM_REQUEST_SIZE, std::mem::size_of::<VmRequestStruct>()); - let mut buf = [0; VM_REQUEST_SIZE]; - let (read, file) = s - .recv_with_fd(&mut buf) - .map_err(|e| VmControlError::Recv(e))?; - if read != VM_REQUEST_SIZE { - return Err(VmControlError::BadSize(read)); - } - // The unwrap() will never fail because it's referencing a buf statically sized to be large - // enough for a VmRequestStruct. - let req: VmRequestStruct = buf.as_mut().get_ref(0).unwrap().load(); - - match req.type_.into() { - VM_REQUEST_TYPE_EXIT => Ok(VmRequest::Exit), - VM_REQUEST_TYPE_REGISTER_MEMORY => { - let fd = file.ok_or(VmControlError::ExpectFd)?; - Ok(VmRequest::RegisterMemory( - MaybeOwnedFd::Owned(fd), - req.size.to_native() as usize, - )) - } - VM_REQUEST_TYPE_UNREGISTER_MEMORY => Ok(VmRequest::UnregisterMemory(req.slot.into())), - VM_REQUEST_TYPE_BALLOON_ADJUST => { - Ok(VmRequest::BalloonAdjust(req.num_pages.to_native() as i32)) - } - VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY => { - Ok(VmRequest::AllocateAndRegisterGpuMemory { - width: req.width.to_native(), - height: req.height.to_native(), - format: req.format.to_native(), - }) - } - _ => Err(VmControlError::InvalidType), - } - } - - /// Send a `VmRequest` over the given socket. - /// - /// After this request is a sent, a `VmResponse` should be received before sending another - /// request. - pub fn send(&self, s: &UnixDatagram) -> VmControlResult<()> { - assert_eq!(VM_REQUEST_SIZE, std::mem::size_of::<VmRequestStruct>()); - let mut req = VmRequestStruct::default(); - let mut fd_buf = [0; 1]; - let mut fd_len = 0; - match self { - &VmRequest::Exit => req.type_ = Le32::from(VM_REQUEST_TYPE_EXIT), - &VmRequest::RegisterMemory(ref fd, size) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_REGISTER_MEMORY); - req.size = Le64::from(size as u64); - fd_buf[0] = fd.as_raw_fd(); - fd_len = 1; - } - &VmRequest::UnregisterMemory(slot) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_UNREGISTER_MEMORY); - req.slot = Le32::from(slot); - } - &VmRequest::BalloonAdjust(pages) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_BALLOON_ADJUST); - req.num_pages = Le32::from(pages as u32); - } - &VmRequest::AllocateAndRegisterGpuMemory { - width, - height, - format, - } => { - req.type_ = Le32::from(VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY); - req.width = Le32::from(width as u32); - req.height = Le32::from(height as u32); - req.format = Le32::from(format as u32); - } - _ => return Err(VmControlError::InvalidType), - } - let mut buf = [0; VM_REQUEST_SIZE]; - buf.as_mut().get_ref(0).unwrap().store(req); - s.send_with_fds(buf.as_ref(), &fd_buf[..fd_len]) - .map_err(|e| VmControlError::Send(e))?; - Ok(()) - } - /// Executes this request on the given Vm and other mutable state. /// /// # Arguments @@ -313,6 +206,7 @@ impl VmRequest { /// Indication of success or failure of a `VmRequest`. /// /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response. +#[derive(MsgOnSocket)] pub enum VmResponse { /// Indicates the request was executed successfully. Ok, @@ -330,373 +224,3 @@ pub enum VmResponse { desc: GpuMemoryDesc, }, } - -const VM_RESPONSE_TYPE_OK: u32 = 1; -const VM_RESPONSE_TYPE_ERR: u32 = 2; -const VM_RESPONSE_TYPE_REGISTER_MEMORY: u32 = 3; -const VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY: u32 = 4; -const VM_RESPONSE_SIZE: usize = 48; - -#[repr(C)] -#[derive(Clone, Copy, Default)] -struct VmResponseStruct { - type_: Le32, - errno: Le32, - pfn: Le64, - slot: Le32, - stride0: Le32, - stride1: Le32, - stride2: Le32, - offset0: Le32, - offset1: Le32, - offset2: Le32, -} - -// Safe because it only has data and has no implicit padding. -unsafe impl DataInit for VmResponseStruct {} - -impl VmResponse { - /// Receive a `VmResponse` from the given socket. - /// - /// This should be called after the sending a `VmRequest` before sending another request. - pub fn recv(s: &UnixDatagram) -> VmControlResult<VmResponse> { - let mut buf = [0; VM_RESPONSE_SIZE]; - let (read, file) = s - .recv_with_fd(&mut buf) - .map_err(|e| VmControlError::Recv(e))?; - if read != VM_RESPONSE_SIZE { - return Err(VmControlError::BadSize(read)); - } - let resp: VmResponseStruct = buf.as_mut().get_ref(0).unwrap().load(); - - match resp.type_.into() { - VM_RESPONSE_TYPE_OK => Ok(VmResponse::Ok), - VM_RESPONSE_TYPE_ERR => Ok(VmResponse::Err(SysError::new( - resp.errno.to_native() as i32 - ))), - VM_RESPONSE_TYPE_REGISTER_MEMORY => Ok(VmResponse::RegisterMemory { - pfn: resp.pfn.into(), - slot: resp.slot.into(), - }), - VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY => { - let fd = file.ok_or(VmControlError::ExpectFd)?; - Ok(VmResponse::AllocateAndRegisterGpuMemory { - fd: MaybeOwnedFd::Owned(fd), - pfn: resp.pfn.into(), - slot: resp.slot.into(), - desc: GpuMemoryDesc { - planes: [ - GpuMemoryPlaneDesc { - stride: resp.stride0.into(), - offset: resp.offset0.into(), - }, - GpuMemoryPlaneDesc { - stride: resp.stride1.into(), - offset: resp.offset1.into(), - }, - GpuMemoryPlaneDesc { - stride: resp.stride2.into(), - offset: resp.offset2.into(), - }, - ], - }, - }) - } - _ => Err(VmControlError::InvalidType), - } - } - - /// Send a `VmResponse` over the given socket. - /// - /// This must be called after receiving a `VmRequest` to indicate the outcome of that request's - /// execution. - pub fn send(&self, s: &UnixDatagram) -> VmControlResult<()> { - let mut resp = VmResponseStruct::default(); - let mut fd_buf = [0; 1]; - let mut fd_len = 0; - match self { - &VmResponse::Ok => resp.type_ = Le32::from(VM_RESPONSE_TYPE_OK), - &VmResponse::Err(e) => { - resp.type_ = Le32::from(VM_RESPONSE_TYPE_ERR); - resp.errno = Le32::from(e.errno().checked_abs().unwrap_or(ERANGE) as u32); - } - &VmResponse::RegisterMemory { pfn, slot } => { - resp.type_ = Le32::from(VM_RESPONSE_TYPE_REGISTER_MEMORY); - resp.pfn = Le64::from(pfn); - resp.slot = Le32::from(slot); - } - &VmResponse::AllocateAndRegisterGpuMemory { - ref fd, - pfn, - slot, - desc, - } => { - fd_buf[0] = fd.as_raw_fd(); - fd_len = 1; - resp.type_ = Le32::from(VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY); - resp.pfn = Le64::from(pfn); - resp.slot = Le32::from(slot); - resp.stride0 = Le32::from(desc.planes[0].stride); - resp.stride1 = Le32::from(desc.planes[1].stride); - resp.stride2 = Le32::from(desc.planes[2].stride); - resp.offset0 = Le32::from(desc.planes[0].offset); - resp.offset1 = Le32::from(desc.planes[1].offset); - resp.offset2 = Le32::from(desc.planes[2].offset); - } - } - let mut buf = [0; VM_RESPONSE_SIZE]; - buf.as_mut().get_ref(0).unwrap().store(resp); - s.send_with_fds(buf.as_ref(), &fd_buf[..fd_len]) - .map_err(|e| VmControlError::Send(e))?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::net::Shutdown; - - use sys_util::kernel_has_memfd; - use sys_util::SharedMemory; - - #[test] - fn request_exit() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmRequest::Exit.send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::Exit => {} - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_register_memory() { - if !kernel_has_memfd() { - return; - } - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let shm_size: usize = 4096; - let mut shm = SharedMemory::new(None).unwrap(); - shm.set_size(shm_size as u64).unwrap(); - VmRequest::RegisterMemory(MaybeOwnedFd::Borrowed(shm.as_raw_fd()), shm_size) - .send(&s1) - .unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::RegisterMemory(MaybeOwnedFd::Owned(fd), size) => { - assert!(fd.as_raw_fd() >= 0); - assert_eq!(size, shm_size); - } - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_unregister_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmRequest::UnregisterMemory(77).send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::UnregisterMemory(slot) => assert_eq!(slot, 77), - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_expect_fd() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let mut bad_request = [0; VM_REQUEST_SIZE]; - bad_request[0] = VM_REQUEST_TYPE_REGISTER_MEMORY as u8; - s2.send_with_fds(bad_request.as_ref(), &[]).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::ExpectFd) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_no_data() { - let (s1, _) = UnixDatagram::pair().expect("failed to create socket pair"); - s1.shutdown(Shutdown::Both).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::BadSize(s)) => assert_eq!(s, 0), - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_bad_size() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; 7].as_ref(), &[]).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::BadSize(_)) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_invalid_type() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; VM_REQUEST_SIZE].as_ref(), &[]) - .unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::InvalidType) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_allocate_and_register_gpu_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let gpu_width: u32 = 32; - let gpu_height: u32 = 32; - let gpu_format: u32 = 0x34325258; - let r = VmRequest::AllocateAndRegisterGpuMemory { - width: gpu_width, - height: gpu_height, - format: gpu_format, - }; - r.send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::AllocateAndRegisterGpuMemory { - width, - height, - format, - } => { - assert_eq!(width, gpu_width); - assert_eq!(height, gpu_width); - assert_eq!(format, gpu_format); - } - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn resp_ok() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmResponse::Ok.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::Ok => {} - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_err() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let r1 = VmResponse::Err(SysError::new(libc::EDESTADDRREQ)); - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::Err(e) => { - assert_eq!(e, SysError::new(libc::EDESTADDRREQ)); - } - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let memory_pfn = 55; - let memory_slot = 66; - let r1 = VmResponse::RegisterMemory { - pfn: memory_pfn, - slot: memory_slot, - }; - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::RegisterMemory { pfn, slot } => { - assert_eq!(pfn, memory_pfn); - assert_eq!(slot, memory_slot); - } - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_no_data() { - let (s1, _) = UnixDatagram::pair().expect("failed to create socket pair"); - s1.shutdown(Shutdown::Both).unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::BadSize(0)); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_bad_size() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; 7].as_ref(), &[]).unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::BadSize(7)); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_invalid_type() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; VM_RESPONSE_SIZE].as_ref(), &[]) - .unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::InvalidType); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_allocate_and_register_gpu_memory() { - if !kernel_has_memfd() { - return; - } - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let shm_size: usize = 4096; - let mut shm = SharedMemory::new(None).unwrap(); - shm.set_size(shm_size as u64).unwrap(); - let memory_pfn = 55; - let memory_slot = 66; - let memory_planes = [ - GpuMemoryPlaneDesc { - stride: 32, - offset: 84, - }, - GpuMemoryPlaneDesc { - stride: 48, - offset: 96, - }, - GpuMemoryPlaneDesc { - stride: 64, - offset: 112, - }, - ]; - let r1 = VmResponse::AllocateAndRegisterGpuMemory { - fd: MaybeOwnedFd::Borrowed(shm.as_raw_fd()), - pfn: memory_pfn, - slot: memory_slot, - desc: GpuMemoryDesc { - planes: memory_planes, - }, - }; - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::AllocateAndRegisterGpuMemory { - fd, - pfn, - slot, - desc, - } => { - assert!(fd.as_raw_fd() >= 0); - assert_eq!(pfn, memory_pfn); - assert_eq!(slot, memory_slot); - assert_eq!(desc.planes, memory_planes); - } - _ => panic!("recv wrong response variant"), - } - } -} |