From d99cd0ae0b21d29d4e5145b889f97e9f6cd11b69 Mon Sep 17 00:00:00 2001 From: Jakub Staron Date: Thu, 11 Apr 2019 14:09:39 -0700 Subject: [PATCH] crosvm: Extracts Wayland commands from from VmRequest. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=None TEST=cargo test TEST=cargo test --package msg_socket TEST=cargo test --package devices TEST=cargo test --package vm_control TEST=tast -verbose run ${IP} vm.CrostiniStartEverything Change-Id: I07f034b1cc41e30b9deae68ea9c510b0923e17a8 Reviewed-on: https://chromium-review.googlesource.com/1565299 Commit-Ready: Jakub StaroĊ„ Tested-by: kokoro Reviewed-by: Zach Reizner --- devices/src/virtio/wl.rs | 30 ++++---- src/linux.rs | 127 ++++++++++++++++++++++----------- vm_control/src/lib.rs | 149 ++++++++++++++++++++++++--------------- 3 files changed, 191 insertions(+), 115 deletions(-) diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs index 77ee1361ae..1e99bfaa18 100644 --- a/devices/src/virtio/wl.rs +++ b/devices/src/virtio/wl.rs @@ -73,7 +73,7 @@ use super::resource_bridge::*; use super::{ DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_WL, VIRTIO_F_VERSION_1, }; -use vm_control::{MaybeOwnedFd, VmControlRequestSocket, VmRequest, VmResponse}; +use vm_control::{MaybeOwnedFd, WlControlRequestSocket, WlDriverRequest, WlDriverResponse}; const VIRTWL_SEND_MAX_ALLOCS: usize = 28; const VIRTIO_WL_CMD_VFD_NEW: u32 = 256; @@ -486,17 +486,17 @@ impl From for WlError { #[derive(Clone)] struct VmRequester { - inner: Rc>, + inner: Rc>, } impl VmRequester { - fn new(vm_socket: VmControlRequestSocket) -> VmRequester { + fn new(vm_socket: WlControlRequestSocket) -> VmRequester { VmRequester { inner: Rc::new(RefCell::new(vm_socket)), } } - fn request(&self, request: VmRequest) -> WlResult { + fn request(&self, request: WlDriverRequest) -> WlResult { let mut inner = self.inner.borrow_mut(); let vm_socket = &mut *inner; vm_socket.send(&request).map_err(WlError::VmControl)?; @@ -727,12 +727,12 @@ impl WlVfd { vfd_shm .set_size(size_page_aligned) .map_err(WlError::AllocSetSize)?; - let register_response = vm.request(VmRequest::RegisterMemory( + let register_response = vm.request(WlDriverRequest::RegisterMemory( MaybeOwnedFd::Borrowed(vfd_shm.as_raw_fd()), vfd_shm.size() as usize, ))?; match register_response { - VmResponse::RegisterMemory { pfn, slot } => { + WlDriverResponse::RegisterMemory { pfn, slot } => { let mut vfd = WlVfd::default(); vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into())); vfd.slot = Some((slot, pfn, vm)); @@ -750,13 +750,13 @@ impl WlVfd { format: u32, ) -> WlResult<(WlVfd, GpuMemoryDesc)> { let allocate_and_register_gpu_memory_response = - vm.request(VmRequest::AllocateAndRegisterGpuMemory { + vm.request(WlDriverRequest::AllocateAndRegisterGpuMemory { width, height, format, })?; match allocate_and_register_gpu_memory_response { - VmResponse::AllocateAndRegisterGpuMemory { + WlDriverResponse::AllocateAndRegisterGpuMemory { fd, pfn, slot, @@ -822,13 +822,13 @@ impl WlVfd { match fd.seek(SeekFrom::End(0)) { Ok(fd_size) => { let size = round_up_to_page_size(fd_size as usize) as u64; - let register_response = vm.request(VmRequest::RegisterMemory( + let register_response = vm.request(WlDriverRequest::RegisterMemory( MaybeOwnedFd::Borrowed(fd.as_raw_fd()), size as usize, ))?; match register_response { - VmResponse::RegisterMemory { pfn, slot } => { + WlDriverResponse::RegisterMemory { pfn, slot } => { let mut vfd = WlVfd::default(); vfd.guest_shared_memory = Some((size, fd)); vfd.slot = Some((slot, pfn, vm)); @@ -963,7 +963,7 @@ impl WlVfd { fn close(&mut self) -> WlResult<()> { if let Some((slot, _, vm)) = self.slot.take() { - vm.request(VmRequest::UnregisterMemory(slot))?; + vm.request(WlDriverRequest::UnregisterMemory(slot))?; } self.socket = None; self.remote_pipe = None; @@ -1002,7 +1002,7 @@ struct WlState { impl WlState { fn new( wayland_path: PathBuf, - vm_socket: VmControlRequestSocket, + vm_socket: WlControlRequestSocket, use_transition_flags: bool, resource_bridge: Option, ) -> WlState { @@ -1486,7 +1486,7 @@ impl Worker { in_queue: Queue, out_queue: Queue, wayland_path: PathBuf, - vm_socket: VmControlRequestSocket, + vm_socket: WlControlRequestSocket, use_transition_flags: bool, resource_bridge: Option, ) -> Worker { @@ -1676,7 +1676,7 @@ impl Worker { pub struct Wl { kill_evt: Option, wayland_path: PathBuf, - vm_socket: Option, + vm_socket: Option, resource_bridge: Option, use_transition_flags: bool, } @@ -1684,7 +1684,7 @@ pub struct Wl { impl Wl { pub fn new>( wayland_path: P, - vm_socket: VmControlRequestSocket, + vm_socket: WlControlRequestSocket, resource_bridge: Option, ) -> Result { Ok(Wl { diff --git a/src/linux.rs b/src/linux.rs index 07cb5a9425..773367248f 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -10,7 +10,7 @@ use std::fmt::{self, Display}; use std::fs::{File, OpenOptions}; use std::io::{self, stdin, Read}; use std::net::Ipv4Addr; -use std::os::unix::io::{FromRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::path::{Path, PathBuf}; use std::str; @@ -35,7 +35,7 @@ use remain::sorted; #[cfg(feature = "gpu-forward")] use resources::Alloc; use sync::{Condvar, Mutex}; -use sys_util::net::{UnixSeqpacketListener, UnlinkUnixSeqpacketListener}; +use sys_util::net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener}; use sys_util::{ self, block_signal, clear_signal, drop_capabilities, error, flock, get_blocked_signals, get_group_id, get_user_id, getegid, geteuid, info, register_signal_handler, set_cpu_affinity, @@ -48,8 +48,8 @@ use vhost; use vm_control::{ BalloonControlCommand, BalloonControlRequestSocket, BalloonControlResponseSocket, DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket, DiskControlResult, - UsbControlSocket, VmControlRequestSocket, VmControlResponseSocket, VmRequest, VmResponse, - VmRunMode, + UsbControlSocket, VmControlResponseSocket, VmRunMode, WlControlRequestSocket, + WlControlResponseSocket, WlDriverRequest, WlDriverResponse, }; use crate::{Config, DiskOption, TouchDeviceOption}; @@ -233,6 +233,27 @@ impl std::error::Error for Error {} type Result = std::result::Result; +enum TaggedControlSocket { + Vm(VmControlResponseSocket), + Wayland(WlControlResponseSocket), +} + +impl AsRef for TaggedControlSocket { + fn as_ref(&self) -> &UnixSeqpacket { + use self::TaggedControlSocket::*; + match &self { + Vm(ref socket) => socket, + Wayland(ref socket) => socket, + } + } +} + +impl AsRawFd for TaggedControlSocket { + fn as_raw_fd(&self) -> RawFd { + self.as_ref().as_raw_fd() + } +} + fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result { // All child jails run in a new user namespace without any users mapped, // they run as nobody unless otherwise configured. @@ -575,7 +596,7 @@ fn create_gpu_device( fn create_wayland_device( cfg: &Config, socket_path: &Path, - socket: VmControlRequestSocket, + socket: WlControlRequestSocket, resource_bridge: Option, ) -> DeviceResult { let wayland_socket_dir = socket_path.parent().ok_or(Error::InvalidWaylandPath)?; @@ -671,7 +692,7 @@ fn create_virtio_devices( cfg: &Config, mem: &GuestMemory, _exit_evt: &EventFd, - wayland_device_socket: VmControlRequestSocket, + wayland_device_socket: WlControlRequestSocket, balloon_device_socket: BalloonControlResponseSocket, disk_device_sockets: &mut Vec, ) -> DeviceResult> { @@ -771,7 +792,7 @@ fn create_devices( cfg: Config, mem: &GuestMemory, exit_evt: &EventFd, - wayland_device_socket: VmControlRequestSocket, + wayland_device_socket: WlControlRequestSocket, balloon_device_socket: BalloonControlResponseSocket, disk_device_sockets: &mut Vec, usb_provider: HostBackendDeviceProvider, @@ -1126,8 +1147,8 @@ pub fn run_config(cfg: Config) -> Result<()> { let mut control_sockets = Vec::new(); let (wayland_host_socket, wayland_device_socket) = - msg_socket::pair::().map_err(Error::CreateSocket)?; - control_sockets.push(wayland_host_socket); + msg_socket::pair::().map_err(Error::CreateSocket)?; + control_sockets.push(TaggedControlSocket::Wayland(wayland_host_socket)); // Balloon gets a special socket so balloon requests can be forwarded from the main process. let (balloon_host_socket, balloon_device_socket) = msg_socket::pair::().map_err(Error::CreateSocket)?; @@ -1213,7 +1234,7 @@ pub fn run_config(cfg: Config) -> Result<()> { fn run_control( mut linux: RunnableLinuxVm, control_server_socket: Option, - mut control_sockets: Vec, + mut control_sockets: Vec, balloon_host_socket: BalloonControlRequestSocket, disk_host_sockets: &[DiskControlRequestSocket], usb_control_socket: UsbControlSocket, @@ -1482,7 +1503,8 @@ fn run_control( }, ) .map_err(Error::PollContextAdd)?; - control_sockets.push(MsgSocket::new(socket)); + control_sockets + .push(TaggedControlSocket::Vm(MsgSocket::new(socket))); } Err(e) => error!("failed to accept socket: {}", e), } @@ -1490,42 +1512,58 @@ fn run_control( } Token::VmControl { index } => { if let Some(socket) = control_sockets.get(index) { - match socket.recv() { - Ok(request) => { - let mut run_mode_opt = None; - let response = request.execute( - &mut linux.vm, - &mut linux.resources, - &mut run_mode_opt, - &balloon_host_socket, - disk_host_sockets, - &usb_control_socket, - ); - if let Err(e) = socket.send(&response) { - error!("failed to send VmResponse: {}", e); - } - if let Some(run_mode) = run_mode_opt { - info!("control socket changed run mode to {}", run_mode); - match run_mode { - VmRunMode::Exiting => { - break 'poll; - } - other => { - run_mode_arc.set_and_notify(other); - for handle in &vcpu_handles { - let _ = handle.kill(SIGRTMIN() + 0); + match socket { + TaggedControlSocket::Vm(socket) => match socket.recv() { + Ok(request) => { + let mut run_mode_opt = None; + let response = request.execute( + &mut run_mode_opt, + &balloon_host_socket, + disk_host_sockets, + &usb_control_socket, + ); + if let Err(e) = socket.send(&response) { + error!("failed to send VmResponse: {}", e); + } + if let Some(run_mode) = run_mode_opt { + info!("control socket changed run mode to {}", run_mode); + match run_mode { + VmRunMode::Exiting => { + break 'poll; + } + other => { + run_mode_arc.set_and_notify(other); + for handle in &vcpu_handles { + let _ = handle.kill(SIGRTMIN() + 0); + } } } } } - } - Err(e) => { - if let MsgError::BadRecvSize { actual: 0, .. } = e { - vm_control_indices_to_remove.push(index); - } else { - error!("failed to recv VmRequest: {}", e); + Err(e) => { + if let MsgError::BadRecvSize { actual: 0, .. } = e { + vm_control_indices_to_remove.push(index); + } else { + error!("failed to recv VmRequest: {}", e); + } } - } + }, + TaggedControlSocket::Wayland(socket) => match socket.recv() { + Ok(request) => { + let response = + request.execute(&mut linux.vm, &mut linux.resources); + if let Err(e) = socket.send(&response) { + error!("failed to send WlControlResponse: {}", e); + } + } + Err(e) => { + if let MsgError::BadRecvSize { actual: 0, .. } = e { + vm_control_indices_to_remove.push(index); + } else { + error!("failed to recv WlControlRequest: {}", e); + } + } + }, } } } @@ -1547,7 +1585,10 @@ fn run_control( // It's possible more data is readable and buffered while the socket is hungup, // so don't delete the socket from the poll context until we're sure all the // data is read. - match control_sockets.get(index).map(|s| s.get_readable_bytes()) { + match control_sockets + .get(index) + .map(|s| s.as_ref().get_readable_bytes()) + { Some(Ok(0)) | Some(Err(_)) => vm_control_indices_to_remove.push(index), Some(Ok(x)) => info!("control index {} has {} bytes readable", index, x), _ => {} diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index 9d68f52c53..25902ea71f 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -158,6 +158,95 @@ impl Display for UsbControlResult { } } +#[derive(MsgOnSocket, Debug)] +pub enum WlDriverRequest { + /// Register shared memory represented by the given fd into guest address space. The response + /// variant is `VmResponse::RegisterMemory`. + RegisterMemory(MaybeOwnedFd, usize), + /// Unregister the given memory slot that was previously registereed with `RegisterMemory`. + UnregisterMemory(u32), + /// Allocate GPU buffer of a given size/format and register the memory into guest address space. + /// The response variant is `VmResponse::AllocateAndRegisterGpuMemory` + AllocateAndRegisterGpuMemory { + width: u32, + height: u32, + format: u32, + }, +} + +impl WlDriverRequest { + /// Executes this request on the given Vm. + /// + /// # Arguments + /// * `vm` - The `Vm` to perform the request on. + /// * `allocator` - Used to allocate addresses. + /// + /// This does not return a result, instead encapsulating the success or failure in a + /// `WlDriverResponse` with the intended purpose of sending the response back over the socket + /// that received this `WlDriverResponse`. + pub fn execute(&self, vm: &mut Vm, sys_allocator: &mut SystemAllocator) -> WlDriverResponse { + use self::WlDriverRequest::*; + match *self { + RegisterMemory(ref fd, size) => match register_memory(vm, sys_allocator, fd, size) { + Ok((pfn, slot)) => WlDriverResponse::RegisterMemory { pfn, slot }, + Err(e) => WlDriverResponse::Err(e), + }, + UnregisterMemory(slot) => match vm.remove_device_memory(slot) { + Ok(_) => WlDriverResponse::Ok, + Err(e) => WlDriverResponse::Err(e), + }, + AllocateAndRegisterGpuMemory { + width, + height, + format, + } => { + let (mut fd, desc) = match sys_allocator.gpu_memory_allocator() { + Some(gpu_allocator) => match gpu_allocator.allocate(width, height, format) { + Ok(v) => v, + Err(e) => return WlDriverResponse::Err(e), + }, + None => return WlDriverResponse::Err(SysError::new(ENODEV)), + }; + // Determine size of buffer using 0 byte seek from end. This is preferred over + // `stride * height` as it's not limited to packed pixel formats. + let size = match fd.seek(SeekFrom::End(0)) { + Ok(v) => v, + Err(e) => return WlDriverResponse::Err(SysError::from(e)), + }; + match register_memory(vm, sys_allocator, &fd, size as usize) { + Ok((pfn, slot)) => WlDriverResponse::AllocateAndRegisterGpuMemory { + fd: MaybeOwnedFd::Owned(fd), + pfn, + slot, + desc, + }, + Err(e) => WlDriverResponse::Err(e), + } + } + } + } +} + +#[derive(MsgOnSocket, Debug)] +pub enum WlDriverResponse { + /// The request to register memory into guest address space was successfully done at page frame + /// number `pfn` and memory slot number `slot`. + RegisterMemory { + pfn: u64, + slot: u32, + }, + /// The request to allocate and register GPU memory into guest address space was successfully + /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`. + AllocateAndRegisterGpuMemory { + fd: MaybeOwnedFd, + pfn: u64, + slot: u32, + desc: GpuMemoryDesc, + }, + Ok, + Err(SysError), +} + pub type BalloonControlRequestSocket = MsgSocket; pub type BalloonControlResponseSocket = MsgSocket<(), BalloonControlCommand>; @@ -166,6 +255,9 @@ pub type DiskControlResponseSocket = MsgSocket; +pub type WlControlRequestSocket = MsgSocket; +pub type WlControlResponseSocket = MsgSocket; + pub type VmControlRequestSocket = MsgSocket; pub type VmControlResponseSocket = MsgSocket; @@ -180,18 +272,6 @@ pub enum VmRequest { Suspend, /// Resume the VM's VCPUs that were previously suspended. Resume, - /// Register shared memory represented by the given fd into guest address space. The response - /// variant is `VmResponse::RegisterMemory`. - RegisterMemory(MaybeOwnedFd, usize), - /// Unregister the given memory slot that was previously registereed with `RegisterMemory`. - UnregisterMemory(u32), - /// Allocate GPU buffer of a given size/format and register the memory into guest address space. - /// The response variant is `VmResponse::AllocateAndRegisterGpuMemory` - AllocateAndRegisterGpuMemory { - width: u32, - height: u32, - format: u32, - }, /// Command for balloon driver. BalloonCommand(BalloonControlCommand), /// Send a command to a disk chosen by `disk_index`. @@ -235,18 +315,11 @@ fn register_memory( impl VmRequest { /// Executes this request on the given Vm and other mutable state. /// - /// # Arguments - /// * `vm` - The `Vm` to perform the request on. - /// * `allocator` - Used to allocate addresses. - /// * `run_mode` - Out argument that is set to a run mode if one was requested. - /// /// This does not return a result, instead encapsulating the success or failure in a /// `VmResponse` with the intended purpose of sending the response back over the socket that /// received this `VmRequest`. pub fn execute( &self, - vm: &mut Vm, - sys_allocator: &mut SystemAllocator, run_mode: &mut Option, balloon_host_socket: &BalloonControlRequestSocket, disk_host_sockets: &[DiskControlRequestSocket], @@ -265,48 +338,10 @@ impl VmRequest { *run_mode = Some(VmRunMode::Running); VmResponse::Ok } - VmRequest::RegisterMemory(ref fd, size) => { - match register_memory(vm, sys_allocator, fd, size) { - Ok((pfn, slot)) => VmResponse::RegisterMemory { pfn, slot }, - Err(e) => VmResponse::Err(e), - } - } - VmRequest::UnregisterMemory(slot) => match vm.remove_device_memory(slot) { - Ok(_) => VmResponse::Ok, - Err(e) => VmResponse::Err(e), - }, VmRequest::BalloonCommand(ref command) => match balloon_host_socket.send(command) { Ok(_) => VmResponse::Ok, Err(_) => VmResponse::Err(SysError::last()), }, - VmRequest::AllocateAndRegisterGpuMemory { - width, - height, - format, - } => { - let (mut fd, desc) = match sys_allocator.gpu_memory_allocator() { - Some(gpu_allocator) => match gpu_allocator.allocate(width, height, format) { - Ok(v) => v, - Err(e) => return VmResponse::Err(e), - }, - None => return VmResponse::Err(SysError::new(ENODEV)), - }; - // Determine size of buffer using 0 byte seek from end. This is preferred over - // `stride * height` as it's not limited to packed pixel formats. - let size = match fd.seek(SeekFrom::End(0)) { - Ok(v) => v, - Err(e) => return VmResponse::Err(SysError::from(e)), - }; - match register_memory(vm, sys_allocator, &fd, size as usize) { - Ok((pfn, slot)) => VmResponse::AllocateAndRegisterGpuMemory { - fd: MaybeOwnedFd::Owned(fd), - pfn, - slot, - desc, - }, - Err(e) => VmResponse::Err(e), - } - } VmRequest::DiskCommand { disk_index, ref command,