From 8d684cad98957751557dd664d203f45c6144672b Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Fri, 20 Mar 2026 18:22:58 +0100 Subject: [PATCH] block: qcow_async: Add QcowAsync struct and constructor Per queue I/O worker that uses io_uring for asynchronous reads against fully allocated clusters. The struct holds the shared metadata, data file, optional backing reader, the io_uring instance and a synthetic completion list. Feature gated on io_uring in lib.rs. Signed-off-by: Anatol Belski --- block/src/lib.rs | 1 + block/src/qcow_async.rs | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/block/src/lib.rs b/block/src/lib.rs index c98f20ae8..811ee974e 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -18,6 +18,7 @@ pub mod fixed_vhd; pub mod fixed_vhd_async; pub mod fixed_vhd_sync; pub mod qcow; +#[cfg(feature = "io_uring")] pub mod qcow_async; pub(crate) mod qcow_common; pub mod qcow_sync; diff --git a/block/src/qcow_async.rs b/block/src/qcow_async.rs index 4e0826c65..b0d93e687 100644 --- a/block/src/qcow_async.rs +++ b/block/src/qcow_async.rs @@ -6,11 +6,15 @@ //! QCOW2 async disk backend. +use std::collections::VecDeque; use std::fs::File; use std::os::fd::{AsFd, AsRawFd}; use std::sync::Arc; use std::{fmt, io}; +use io_uring::IoUring; +use vmm_sys_util::eventfd::EventFd; + use crate::async_io::{BorrowedDiskFd, DiskFileError}; use crate::disk_file; use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; @@ -121,3 +125,46 @@ impl disk_file::Resizable for QcowDiskAsync { } impl disk_file::DiskFile for QcowDiskAsync {} + +/// Per queue QCOW2 I/O worker using io_uring. +/// +/// Reads against fully allocated single mapping clusters are submitted +/// to io_uring for true asynchronous completion. All other cluster +/// types (zero, compressed, backing) and multi mapping reads fall back +/// to synchronous I/O with synthetic completions. +/// +/// Writes are synchronous because metadata allocation must complete +/// before the host offset is known. +pub struct QcowAsync { + metadata: Arc, + data_file: QcowRawFile, + backing_file: Option>, + sparse: bool, + io_uring: IoUring, + eventfd: EventFd, + completion_list: VecDeque<(u64, i32)>, +} + +impl QcowAsync { + fn new( + metadata: Arc, + data_file: QcowRawFile, + backing_file: Option>, + sparse: bool, + ring_depth: u32, + ) -> io::Result { + let io_uring = IoUring::new(ring_depth)?; + let eventfd = EventFd::new(libc::EFD_NONBLOCK)?; + io_uring.submitter().register_eventfd(eventfd.as_raw_fd())?; + + Ok(QcowAsync { + metadata, + data_file, + backing_file, + sparse, + io_uring, + eventfd, + completion_list: VecDeque::new(), + }) + } +}