build: Allow disabling io_uring

This gives users the chance to reduce the number of dependencies
included, which is generally good practice and also reduces code size.

Furthermore, `io_uring` specifically is a strong contender for something
one may wish to disable due to the syscall API's many security issues[1]

 [1]: https://security.googleblog.com/2023/06/learnings-from-kctf-vrps-42-linux.html

Signed-off-by: Manish Goregaokar <manishsmail@gmail.com>
This commit is contained in:
Manish Goregaokar 2023-07-10 11:55:55 +02:00 committed by Bo Chen
parent d2e42a0ed4
commit 6fdba7ca11
7 changed files with 85 additions and 48 deletions

1
Cargo.lock generated
View File

@ -2151,7 +2151,6 @@ dependencies = [
"byteorder",
"epoll",
"event_monitor",
"io-uring",
"libc",
"log",
"net_gen",

View File

@ -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"]

View File

@ -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" }

View File

@ -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<F>

View File

@ -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" }

View File

@ -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"]

View File

@ -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<dyn DiskFile>
#[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<dyn DiskFile>
}
} 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<dyn DiskFile>
#[cfg(not(feature = "io_uring"))]
unreachable!("Checked in if statement above");
#[cfg(feature = "io_uring")]
{
Box::new(RawFileDisk::new(file)) as Box<dyn DiskFile>
}
} else {
info!("Using synchronous RAW disk file");
Box::new(RawFileDiskSync::new(file)) as Box<dyn DiskFile>