diff --git a/Cargo.lock b/Cargo.lock index 4921ab613..fcf953e07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1613,6 +1613,7 @@ dependencies = [ "anyhow", "arc-swap", "arch", + "block_util", "clap", "credibility", "devices", diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 7a34907e5..98bed7117 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -19,6 +19,7 @@ clap = "2.33.1" acpi_tables = { path = "../acpi_tables", optional = true } anyhow = "1.0" arch = { path = "../arch" } +block_util = { path = "../block_util" } devices = { path = "../devices" } epoll = ">=4.0.1" hypervisor = { path = "../hypervisor" } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 873f28344..3838657aa 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -32,6 +32,7 @@ use arch::layout; use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START}; #[cfg(target_arch = "aarch64")] use arch::DeviceType; +use block_util::block_io_uring_is_supported; #[cfg(target_arch = "aarch64")] use devices::gic; #[cfg(target_arch = "x86_64")] @@ -1662,70 +1663,95 @@ impl DeviceManager { ) .map_err(DeviceManagerError::Disk)?; - let mut raw_img = qcow::RawFile::new(image, disk_cfg.direct); + let mut raw_img = qcow::RawFile::new(image.try_clone().unwrap(), disk_cfg.direct); let image_type = qcow::detect_image_type(&mut raw_img) .map_err(DeviceManagerError::DetectImageType)?; - match image_type { + let (virtio_device, migratable_device) = match image_type { ImageType::Raw => { - let dev = virtio_devices::Block::new( - id.clone(), - raw_img, - disk_cfg - .path - .as_ref() - .ok_or(DeviceManagerError::NoDiskPath)? - .clone(), - disk_cfg.readonly, - disk_cfg.iommu, - disk_cfg.num_queues, - disk_cfg.queue_size, - ) - .map_err(DeviceManagerError::CreateVirtioBlock)?; + // Use asynchronous backend relying on io_uring if the + // syscalls are supported. + if block_io_uring_is_supported() { + let dev = Arc::new(Mutex::new( + virtio_devices::BlockIoUring::new( + id.clone(), + image, + disk_cfg + .path + .as_ref() + .ok_or(DeviceManagerError::NoDiskPath)? + .clone(), + disk_cfg.readonly, + disk_cfg.iommu, + disk_cfg.num_queues, + disk_cfg.queue_size, + ) + .map_err(DeviceManagerError::CreateVirtioBlock)?, + )); - let block = Arc::new(Mutex::new(dev)); + ( + Arc::clone(&dev) as VirtioDeviceArc, + dev as Arc>, + ) + } else { + let dev = Arc::new(Mutex::new( + virtio_devices::Block::new( + id.clone(), + raw_img, + disk_cfg + .path + .as_ref() + .ok_or(DeviceManagerError::NoDiskPath)? + .clone(), + disk_cfg.readonly, + disk_cfg.iommu, + disk_cfg.num_queues, + disk_cfg.queue_size, + ) + .map_err(DeviceManagerError::CreateVirtioBlock)?, + )); - // Fill the device tree with a new node. In case of restore, we - // know there is nothing to do, so we can simply override the - // existing entry. - self.device_tree - .lock() - .unwrap() - .insert(id.clone(), device_node!(id, block)); - - Ok((Arc::clone(&block) as VirtioDeviceArc, disk_cfg.iommu, id)) + ( + Arc::clone(&dev) as VirtioDeviceArc, + dev as Arc>, + ) + } } ImageType::Qcow2 => { let qcow_img = QcowFile::from(raw_img).map_err(DeviceManagerError::QcowDeviceCreate)?; - let dev = virtio_devices::Block::new( - id.clone(), - qcow_img, - disk_cfg - .path - .as_ref() - .ok_or(DeviceManagerError::NoDiskPath)? - .clone(), - disk_cfg.readonly, - disk_cfg.iommu, - disk_cfg.num_queues, - disk_cfg.queue_size, + let dev = Arc::new(Mutex::new( + virtio_devices::Block::new( + id.clone(), + qcow_img, + disk_cfg + .path + .as_ref() + .ok_or(DeviceManagerError::NoDiskPath)? + .clone(), + disk_cfg.readonly, + disk_cfg.iommu, + disk_cfg.num_queues, + disk_cfg.queue_size, + ) + .map_err(DeviceManagerError::CreateVirtioBlock)?, + )); + + ( + Arc::clone(&dev) as VirtioDeviceArc, + dev as Arc>, ) - .map_err(DeviceManagerError::CreateVirtioBlock)?; - - let block = Arc::new(Mutex::new(dev)); - - // Fill the device tree with a new node. In case of restore, we - // know there is nothing to do, so we can simply override the - // existing entry. - self.device_tree - .lock() - .unwrap() - .insert(id.clone(), device_node!(id, block)); - - Ok((Arc::clone(&block) as VirtioDeviceArc, disk_cfg.iommu, id)) } - } + }; + // Fill the device tree with a new node. In case of restore, we + // know there is nothing to do, so we can simply override the + // existing entry. + self.device_tree + .lock() + .unwrap() + .insert(id.clone(), device_node!(id, migratable_device)); + + Ok((virtio_device, disk_cfg.iommu, id)) } } diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index 5dc0358d9..25b979044 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -36,6 +36,11 @@ macro_rules! or { ($($x:expr),*) => (vec![$($x),*]) } +// Define io_uring syscalls as they are not yet part of libc. +const SYS_IO_URING_SETUP: i64 = 425; +const SYS_IO_URING_ENTER: i64 = 426; +const SYS_IO_URING_REGISTER: i64 = 427; + // See include/uapi/asm-generic/ioctls.h in the kernel code. const TCGETS: u64 = 0x5401; const TCSETS: u64 = 0x5402; @@ -279,6 +284,9 @@ pub fn vmm_thread_filter() -> Result { allow_syscall(libc::SYS_gettimeofday), allow_syscall(libc::SYS_getuid), allow_syscall_if(libc::SYS_ioctl, create_vmm_ioctl_seccomp_rule()?), + allow_syscall(SYS_IO_URING_ENTER), + allow_syscall(SYS_IO_URING_SETUP), + allow_syscall(SYS_IO_URING_REGISTER), allow_syscall(libc::SYS_listen), allow_syscall(libc::SYS_lseek), allow_syscall(libc::SYS_madvise),