From aa5756669a8331420b84a22e29ddbfc13b791da5 Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Wed, 15 Aug 2018 10:46:32 -0700 Subject: devices: allow virtio-wayland to use virtgpu resources This change uses the resource bridge between virtio-gpu and virtio-cpu to send resources over the host wayland connection that originated from the virtio-gpu device. This will help support gpu accelerated wayland surfaces. BUG=chromium:875998 TEST=wayland-simple-egl Change-Id: I3340ecef438779be5cb3643b2de8bb8c33097d75 Reviewed-on: https://chromium-review.googlesource.com/1182793 Commit-Ready: ChromeOS CL Exonerator Bot Tested-by: Zach Reizner Reviewed-by: Zach Reizner --- src/linux.rs | 179 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/linux.rs b/src/linux.rs index d4094fa..1cb99cc 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -382,6 +382,98 @@ fn create_virtio_devs( } } + #[cfg(feature = "gpu")] + let mut resource_bridge_wl_socket: Option< + devices::virtio::resource_bridge::ResourceRequestSocket, + > = None; + #[cfg(feature = "gpu")] + { + if cfg.gpu { + if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() { + let (wl_socket, gpu_socket) = + devices::virtio::resource_bridge::pair().map_err(Error::CreateSocket)?; + resource_bridge_wl_socket = Some(wl_socket); + + let jailed_wayland_path = Path::new("/wayland-0"); + + let gpu_box = Box::new(devices::virtio::Gpu::new( + _exit_evt.try_clone().map_err(Error::CloneEventFd)?, + Some(gpu_socket), + if cfg.multiprocess { + &jailed_wayland_path + } else { + wayland_socket_path.as_path() + }, + )); + + let jail = if cfg.multiprocess { + let policy_path: PathBuf = cfg.seccomp_policy_dir.join("gpu_device.policy"); + let mut jail = create_base_minijail(empty_root_path, &policy_path)?; + + // Create a tmpfs in the device's root directory so that we can bind mount the + // dri directory into it. The size=67108864 is size=64*1024*1024 or size=64MB. + jail.mount_with_data( + Path::new("none"), + Path::new("/"), + "tmpfs", + (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize, + "size=67108864", + ).unwrap(); + + // Device nodes required for DRM. + let sys_dev_char_path = Path::new("/sys/dev/char"); + jail.mount_bind(sys_dev_char_path, sys_dev_char_path, false) + .unwrap(); + let sys_devices_path = Path::new("/sys/devices"); + jail.mount_bind(sys_devices_path, sys_devices_path, false) + .unwrap(); + let drm_dri_path = Path::new("/dev/dri"); + jail.mount_bind(drm_dri_path, drm_dri_path, false).unwrap(); + + // Libraries that are required when mesa drivers are dynamically loaded. + let lib_path = Path::new("/lib64"); + jail.mount_bind(lib_path, lib_path, false).unwrap(); + let usr_lib_path = Path::new("/usr/lib64"); + jail.mount_bind(usr_lib_path, usr_lib_path, false).unwrap(); + + // Bind mount the wayland socket into jail's root. This is necessary since each + // new wayland context must open() the socket. + jail.mount_bind(wayland_socket_path.as_path(), jailed_wayland_path, true) + .unwrap(); + + // Set the uid/gid for the jailed process, and give a basic id map. This + // is required for the above bind mount to work. + let crosvm_user_group = CStr::from_bytes_with_nul(b"crosvm\0").unwrap(); + let crosvm_uid = match get_user_id(&crosvm_user_group) { + Ok(u) => u, + Err(e) => { + warn!("falling back to current user id for gpu: {:?}", e); + geteuid() + } + }; + let crosvm_gid = match get_group_id(&crosvm_user_group) { + Ok(u) => u, + Err(e) => { + warn!("falling back to current group id for gpu: {:?}", e); + getegid() + } + }; + jail.change_uid(crosvm_uid); + jail.change_gid(crosvm_gid); + jail.uidmap(&format!("{0} {0} 1", crosvm_uid)) + .map_err(Error::SettingUidMap)?; + jail.gidmap(&format!("{0} {0} 1", crosvm_gid)) + .map_err(Error::SettingGidMap)?; + + Some(jail) + } else { + None + }; + devs.push(VirtioDeviceStub { dev: gpu_box, jail }); + } + } + } + if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() { let wayland_socket_dir = wayland_socket_path .parent() @@ -392,6 +484,9 @@ fn create_virtio_devs( let jailed_wayland_dir = Path::new("/wayland"); let jailed_wayland_path = jailed_wayland_dir.join(wayland_socket_name); + #[cfg(not(feature = "gpu"))] + let resource_bridge_wl_socket = None; + let wl_box = Box::new( devices::virtio::Wl::new( if cfg.multiprocess { @@ -400,6 +495,7 @@ fn create_virtio_devs( wayland_socket_path.as_path() }, wayland_device_socket, + resource_bridge_wl_socket, ).map_err(Error::WaylandDeviceNew)?, ); @@ -474,89 +570,6 @@ fn create_virtio_devs( }); } - #[cfg(feature = "gpu")] - { - if cfg.gpu { - if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() { - let jailed_wayland_path = Path::new("/wayland-0"); - - let gpu_box = Box::new(devices::virtio::Gpu::new( - _exit_evt.try_clone().map_err(Error::CloneEventFd)?, - if cfg.multiprocess { - &jailed_wayland_path - } else { - wayland_socket_path.as_path() - }, - )); - - let jail = if cfg.multiprocess { - let policy_path: PathBuf = cfg.seccomp_policy_dir.join("gpu_device.policy"); - let mut jail = create_base_minijail(empty_root_path, &policy_path)?; - - // Create a tmpfs in the device's root directory so that we can bind mount the - // dri directory into it. The size=67108864 is size=64*1024*1024 or size=64MB. - jail.mount_with_data( - Path::new("none"), - Path::new("/"), - "tmpfs", - (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize, - "size=67108864", - ).unwrap(); - - // Device nodes required for DRM. - let sys_dev_char_path = Path::new("/sys/dev/char"); - jail.mount_bind(sys_dev_char_path, sys_dev_char_path, false) - .unwrap(); - let sys_devices_path = Path::new("/sys/devices"); - jail.mount_bind(sys_devices_path, sys_devices_path, false) - .unwrap(); - let drm_dri_path = Path::new("/dev/dri"); - jail.mount_bind(drm_dri_path, drm_dri_path, false).unwrap(); - - // Libraries that are required when mesa drivers are dynamically loaded. - let lib_path = Path::new("/lib64"); - jail.mount_bind(lib_path, lib_path, false).unwrap(); - let usr_lib_path = Path::new("/usr/lib64"); - jail.mount_bind(usr_lib_path, usr_lib_path, false).unwrap(); - - // Bind mount the wayland socket into jail's root. This is necessary since each - // new wayland context must open() the socket. - jail.mount_bind(wayland_socket_path.as_path(), jailed_wayland_path, true) - .unwrap(); - - // Set the uid/gid for the jailed process, and give a basic id map. This - // is required for the above bind mount to work. - let crosvm_user_group = CStr::from_bytes_with_nul(b"crosvm\0").unwrap(); - let crosvm_uid = match get_user_id(&crosvm_user_group) { - Ok(u) => u, - Err(e) => { - warn!("falling back to current user id for gpu: {:?}", e); - geteuid() - } - }; - let crosvm_gid = match get_group_id(&crosvm_user_group) { - Ok(u) => u, - Err(e) => { - warn!("falling back to current group id for gpu: {:?}", e); - getegid() - } - }; - jail.change_uid(crosvm_uid); - jail.change_gid(crosvm_gid); - jail.uidmap(&format!("{0} {0} 1", crosvm_uid)) - .map_err(Error::SettingUidMap)?; - jail.gidmap(&format!("{0} {0} 1", crosvm_gid)) - .map_err(Error::SettingGidMap)?; - - Some(jail) - } else { - None - }; - devs.push(VirtioDeviceStub { dev: gpu_box, jail }); - } - } - } - let chronos_user_group = CStr::from_bytes_with_nul(b"chronos\0").unwrap(); let chronos_uid = match get_user_id(&chronos_user_group) { Ok(u) => u, -- cgit 1.4.1