diff --git a/Cargo.lock b/Cargo.lock index e5a730ff3..57ab7d67d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2151,7 +2151,6 @@ dependencies = [ "byteorder", "epoll", "event_monitor", - "io-uring", "libc", "log", "net_gen", diff --git a/Cargo.toml b/Cargo.toml index 32f0b0e8f..99eda4430 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,10 +66,11 @@ test_infra = { path = "test_infra" } wait-timeout = "0.2.0" [features] -default = ["kvm"] +default = ["kvm", "io_uring"] dbus_api = ["zbus", "vmm/dbus_api"] dhat-heap = ["dhat"] # For heap profiling guest_debug = ["vmm/guest_debug"] +io_uring = ["vmm/io_uring"] kvm = ["vmm/kvm"] mshv = ["vmm/mshv"] tdx = ["vmm/tdx"] diff --git a/block_util/Cargo.toml b/block_util/Cargo.toml index dbeb5eece..ef76b73a1 100644 --- a/block_util/Cargo.toml +++ b/block_util/Cargo.toml @@ -6,9 +6,10 @@ edition = "2021" [features] default = [] +io_uring = ["dep:io-uring"] [dependencies] -io-uring = "0.5.13" +io-uring = { version = "0.5.13", optional = true } libc = "0.2.139" log = "0.4.17" qcow = { path = "../qcow" } diff --git a/block_util/src/lib.rs b/block_util/src/lib.rs index 1bd16f9b4..067adbeec 100644 --- a/block_util/src/lib.rs +++ b/block_util/src/lib.rs @@ -12,15 +12,22 @@ extern crate log; pub mod async_io; +#[cfg(feature = "io_uring")] +/// Enabled with the `"io_uring"` feature pub mod fixed_vhd_async; pub mod fixed_vhd_sync; pub mod qcow_sync; +#[cfg(feature = "io_uring")] +/// Async primitives based on `io-uring` +/// +/// Enabled with the `"io_uring"` feature pub mod raw_async; pub mod raw_sync; pub mod vhd; pub mod vhdx_sync; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; +#[cfg(feature = "io_uring")] use io_uring::{opcode, IoUring, Probe}; use smallvec::SmallVec; use std::alloc::{alloc_zeroed, dealloc, Layout}; @@ -543,50 +550,59 @@ unsafe impl ByteValued for VirtioBlockGeometry {} /// Check if io_uring for block device can be used on the current system, as /// it correctly supports the expected io_uring features. pub fn block_io_uring_is_supported() -> bool { - let error_msg = "io_uring not supported:"; + #[cfg(not(feature = "io_uring"))] + { + info!("io_uring is disabled by crate features"); + false + } - // Check we can create an io_uring instance, which effectively verifies - // that io_uring_setup() syscall is supported. - let io_uring = match IoUring::new(1) { - Ok(io_uring) => io_uring, - Err(e) => { - info!("{} failed to create io_uring instance: {}", error_msg, e); + #[cfg(feature = "io_uring")] + { + let error_msg = "io_uring not supported:"; + + // Check we can create an io_uring instance, which effectively verifies + // that io_uring_setup() syscall is supported. + let io_uring = match IoUring::new(1) { + Ok(io_uring) => io_uring, + Err(e) => { + info!("{} failed to create io_uring instance: {}", error_msg, e); + return false; + } + }; + + let submitter = io_uring.submitter(); + + let mut probe = Probe::new(); + + // Check we can register a probe to validate supported operations. + match submitter.register_probe(&mut probe) { + Ok(_) => {} + Err(e) => { + info!("{} failed to register a probe: {}", error_msg, e); + return false; + } + } + + // Check IORING_OP_FSYNC is supported + if !probe.is_supported(opcode::Fsync::CODE) { + info!("{} IORING_OP_FSYNC operation not supported", error_msg); return false; } - }; - let submitter = io_uring.submitter(); - - let mut probe = Probe::new(); - - // Check we can register a probe to validate supported operations. - match submitter.register_probe(&mut probe) { - Ok(_) => {} - Err(e) => { - info!("{} failed to register a probe: {}", error_msg, e); + // Check IORING_OP_READV is supported + if !probe.is_supported(opcode::Readv::CODE) { + info!("{} IORING_OP_READV operation not supported", error_msg); return false; } - } - // Check IORING_OP_FSYNC is supported - if !probe.is_supported(opcode::Fsync::CODE) { - info!("{} IORING_OP_FSYNC operation not supported", error_msg); - return false; - } + // Check IORING_OP_WRITEV is supported + if !probe.is_supported(opcode::Writev::CODE) { + info!("{} IORING_OP_WRITEV operation not supported", error_msg); + return false; + } - // Check IORING_OP_READV is supported - if !probe.is_supported(opcode::Readv::CODE) { - info!("{} IORING_OP_READV operation not supported", error_msg); - return false; + true } - - // Check IORING_OP_WRITEV is supported - if !probe.is_supported(opcode::Writev::CODE) { - info!("{} IORING_OP_WRITEV operation not supported", error_msg); - return false; - } - - true } pub trait AsyncAdaptor diff --git a/virtio-devices/Cargo.toml b/virtio-devices/Cargo.toml index 6bda4bb41..d30a86835 100644 --- a/virtio-devices/Cargo.toml +++ b/virtio-devices/Cargo.toml @@ -14,7 +14,6 @@ block_util = { path = "../block_util" } byteorder = "1.4.3" epoll = "4.3.3" event_monitor = { path = "../event_monitor" } -io-uring = "0.5.13" libc = "0.2.139" log = "0.4.17" net_gen = { path = "../net_gen" } diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 88fb0df35..ce5958b3f 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" default = [] dbus_api = ["blocking", "futures", "zbus"] guest_debug = ["kvm", "gdbstub", "gdbstub_arch"] +io_uring = ["block_util/io_uring"] kvm = ["hypervisor/kvm", "vfio-ioctls/kvm", "vm-device/kvm", "pci/kvm"] mshv = ["hypervisor/mshv", "vfio-ioctls/mshv", "vm-device/mshv", "pci/mshv"] tdx = ["arch/tdx", "hypervisor/tdx"] diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 4b1568999..d17f0e0d8 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -36,9 +36,11 @@ use arch::NumaNodes; use arch::{DeviceType, MmioDeviceInfo}; use block_util::{ async_io::DiskFile, block_io_uring_is_supported, detect_image_type, - fixed_vhd_async::FixedVhdDiskAsync, fixed_vhd_sync::FixedVhdDiskSync, qcow_sync::QcowDiskSync, - raw_async::RawFileDisk, raw_sync::RawFileDiskSync, vhdx_sync::VhdxDiskSync, ImageType, + fixed_vhd_sync::FixedVhdDiskSync, qcow_sync::QcowDiskSync, raw_sync::RawFileDiskSync, + vhdx_sync::VhdxDiskSync, ImageType, }; +#[cfg(feature = "io_uring")] +use block_util::{fixed_vhd_async::FixedVhdDiskAsync, raw_async::RawFileDisk}; #[cfg(target_arch = "aarch64")] use devices::gic; #[cfg(target_arch = "x86_64")] @@ -2225,12 +2227,21 @@ impl DeviceManager { ImageType::FixedVhd => { // Use asynchronous backend relying on io_uring if the // syscalls are supported. - if !disk_cfg.disable_io_uring && self.io_uring_is_supported() { + if cfg!(feature = "io_uring") + && !disk_cfg.disable_io_uring + && self.io_uring_is_supported() + { info!("Using asynchronous fixed VHD disk file (io_uring)"); - Box::new( - FixedVhdDiskAsync::new(file) - .map_err(DeviceManagerError::CreateFixedVhdDiskAsync)?, - ) as Box + + #[cfg(not(feature = "io_uring"))] + unreachable!("Checked in if statement above"); + #[cfg(feature = "io_uring")] + { + Box::new( + FixedVhdDiskAsync::new(file) + .map_err(DeviceManagerError::CreateFixedVhdDiskAsync)?, + ) as Box + } } else { info!("Using synchronous fixed VHD disk file"); Box::new( @@ -2242,9 +2253,18 @@ impl DeviceManager { ImageType::Raw => { // Use asynchronous backend relying on io_uring if the // syscalls are supported. - if !disk_cfg.disable_io_uring && self.io_uring_is_supported() { + if cfg!(feature = "io_uring") + && !disk_cfg.disable_io_uring + && self.io_uring_is_supported() + { info!("Using asynchronous RAW disk file (io_uring)"); - Box::new(RawFileDisk::new(file)) as Box + + #[cfg(not(feature = "io_uring"))] + unreachable!("Checked in if statement above"); + #[cfg(feature = "io_uring")] + { + Box::new(RawFileDisk::new(file)) as Box + } } else { info!("Using synchronous RAW disk file"); Box::new(RawFileDiskSync::new(file)) as Box