From 587093ddfd400767a3183b12ab471983bd10896d Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Fri, 24 Apr 2026 10:32:05 +0200 Subject: [PATCH] block: qcow: Remove old wrapper structs, restrict visibility Delete QcowDiskSync and QcowDiskAsync wrapper structs along with their DiskFile trait impls. Only the AsyncIo worker structs QcowSync and QcowAsync remain. Reduce module visibility of qcow_sync and qcow_async to pub(crate). Signed-off-by: Anatol Belski --- block/src/lib.rs | 4 +- block/src/qcow/mod.rs | 3 +- block/src/qcow_async.rs | 146 +++------------------------------------- block/src/qcow_sync.rs | 134 +----------------------------------- 4 files changed, 14 insertions(+), 273 deletions(-) diff --git a/block/src/lib.rs b/block/src/lib.rs index d86b40129..a58c445ef 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -21,10 +21,10 @@ pub mod fixed_vhd_disk; pub mod fixed_vhd_sync; pub mod qcow; #[cfg(feature = "io_uring")] -pub mod qcow_async; +pub(crate) mod qcow_async; pub(crate) mod qcow_common; pub mod qcow_disk; -pub mod qcow_sync; +pub(crate) mod qcow_sync; #[cfg(feature = "io_uring")] pub(crate) mod raw_async; pub(crate) mod raw_async_aio; diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs index 32c2b0648..b9a63d1f9 100644 --- a/block/src/qcow/mod.rs +++ b/block/src/qcow/mod.rs @@ -372,8 +372,7 @@ impl Debug for BackingFile { /// Parses and validates a QCOW2 image file, returning the metadata, backing /// file and sparse flag. /// -/// This shared constructor is used by both QcowFile for sequential I/O -/// and QcowDiskSync for lock based parallel I/O. +/// Used by [`QcowFile`] and [`QcowDisk`] constructors. pub(crate) fn parse_qcow( mut file: RawFile, max_nesting_depth: u32, diff --git a/block/src/qcow_async.rs b/block/src/qcow_async.rs index 8da8b1ebe..bf435105f 100644 --- a/block/src/qcow_async.rs +++ b/block/src/qcow_async.rs @@ -8,157 +8,25 @@ use std::cmp::{max, min}; use std::collections::VecDeque; -use std::fs::File; -use std::io::Error; -use std::os::fd::{AsFd, AsRawFd}; +use std::io; +use std::os::unix::io::AsRawFd; use std::sync::Arc; -use std::{fmt, io}; use io_uring::{IoUring, opcode, types}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt}; -use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFileError}; -use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; -use crate::qcow::backing::shared_backing_from; +use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; use crate::qcow::decoder::Decoder; use crate::qcow::metadata::{ BackingRead, ClusterReadMapping, ClusterWriteMapping, DeallocAction, QcowMetadata, }; use crate::qcow::qcow_raw_file::QcowRawFile; -use crate::qcow::{MAX_NESTING_DEPTH, RawFile, parse_qcow}; use crate::qcow_common::{ AlignedBuf, aligned_pread, aligned_pwrite, decompress_cluster, gather_from_iovecs_into, pread_alloc, pread_exact, pwrite_all, scatter_to_iovecs, zero_fill_iovecs, }; -use crate::{BatchRequest, RequestType, SECTOR_SIZE, disk_file}; - -/// Device level handle for a QCOW2 image. -/// -/// Owns the parsed metadata and backing file chain. One instance is -/// created per disk and shared across virtio queues. -pub struct QcowDiskAsync { - metadata: Arc, - backing_file: Option>, - sparse: bool, - data_raw_file: QcowRawFile, -} - -impl fmt::Debug for QcowDiskAsync { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("QcowDiskAsync") - .field("sparse", &self.sparse) - .field("has_backing", &self.backing_file.is_some()) - .finish_non_exhaustive() - } -} - -impl QcowDiskAsync { - pub fn new( - file: File, - direct_io: bool, - backing_files: bool, - sparse: bool, - ) -> BlockResult { - let max_nesting_depth = if backing_files { MAX_NESTING_DEPTH } else { 0 }; - let (inner, backing_file, sparse) = - parse_qcow(RawFile::new(file, direct_io), max_nesting_depth, sparse).map_err(|e| { - let e = if !backing_files && matches!(e.kind(), BlockErrorKind::Overflow) { - e.with_kind(BlockErrorKind::UnsupportedFeature) - } else { - e - }; - e.with_op(ErrorOp::Open) - })?; - let data_raw_file = inner.raw_file.clone(); - Ok(QcowDiskAsync { - metadata: Arc::new(QcowMetadata::new(inner)), - backing_file: backing_file.map(shared_backing_from).transpose()?, - sparse, - data_raw_file, - }) - } -} - -impl Drop for QcowDiskAsync { - fn drop(&mut self) { - self.metadata.shutdown(); - } -} - -impl disk_file::DiskSize for QcowDiskAsync { - fn logical_size(&self) -> BlockResult { - Ok(self.metadata.virtual_size()) - } -} - -impl disk_file::PhysicalSize for QcowDiskAsync { - fn physical_size(&self) -> BlockResult { - Ok(self.data_raw_file.physical_size()?) - } -} - -impl disk_file::DiskFd for QcowDiskAsync { - fn fd(&self) -> BorrowedDiskFd<'_> { - BorrowedDiskFd::new(self.data_raw_file.as_fd().as_raw_fd()) - } -} - -impl disk_file::Geometry for QcowDiskAsync {} - -impl disk_file::SparseCapable for QcowDiskAsync { - fn supports_sparse_operations(&self) -> bool { - true - } - - fn supports_zero_flag(&self) -> bool { - true - } -} - -impl disk_file::Resizable for QcowDiskAsync { - fn resize(&mut self, size: u64) -> BlockResult<()> { - if self.backing_file.is_some() { - return Err(BlockError::new( - BlockErrorKind::UnsupportedFeature, - DiskFileError::ResizeError(io::Error::other( - "resize not supported with backing file", - )), - ) - .with_op(ErrorOp::Resize)); - } - self.metadata.resize(size).map_err(|e| { - BlockError::new(BlockErrorKind::Io, DiskFileError::ResizeError(e)) - .with_op(ErrorOp::Resize) - }) - } -} - -impl disk_file::DiskFile for QcowDiskAsync {} - -impl disk_file::AsyncDiskFile for QcowDiskAsync { - fn try_clone(&self) -> BlockResult> { - Ok(Box::new(QcowDiskAsync { - metadata: Arc::clone(&self.metadata), - backing_file: self.backing_file.as_ref().map(Arc::clone), - sparse: self.sparse, - data_raw_file: self.data_raw_file.clone(), - })) - } - - fn create_async_io(&self, ring_depth: u32) -> BlockResult> { - Ok(Box::new( - QcowAsync::new( - Arc::clone(&self.metadata), - self.data_raw_file.clone(), - self.backing_file.as_ref().map(Arc::clone), - self.sparse, - ring_depth, - ) - .map_err(|e| BlockError::new(BlockErrorKind::Io, DiskFileError::NewAsyncIo(e)))?, - )) - } -} +use crate::{BatchRequest, RequestType, SECTOR_SIZE}; /// Per queue QCOW2 I/O worker using io_uring. /// @@ -271,7 +139,7 @@ impl AsyncIo for QcowAsync { .user_data(user_data), ) .map_err(|_| { - AsyncIoError::ReadVectored(Error::other("Submission queue is full")) + AsyncIoError::ReadVectored(io::Error::other("Submission queue is full")) })?; }; @@ -418,7 +286,9 @@ impl AsyncIo for QcowAsync { .user_data(req.user_data), ) .map_err(|_| { - AsyncIoError::ReadVectored(Error::other("Submission queue is full")) + AsyncIoError::ReadVectored(io::Error::other( + "Submission queue is full", + )) })?; } needs_submit = true; diff --git a/block/src/qcow_sync.rs b/block/src/qcow_sync.rs index 53701cfd4..9e183dee1 100644 --- a/block/src/qcow_sync.rs +++ b/block/src/qcow_sync.rs @@ -4,156 +4,28 @@ use std::cmp::min; use std::collections::VecDeque; -use std::fs::File; -use std::os::fd::{AsFd, AsRawFd}; +use std::os::unix::io::AsRawFd; use std::sync::Arc; -use std::{fmt, io}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt}; -use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFileError}; -use crate::disk_file; -use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; -use crate::qcow::backing::shared_backing_from; +use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; use crate::qcow::decoder::Decoder; use crate::qcow::metadata::{ BackingRead, ClusterReadMapping, ClusterWriteMapping, DeallocAction, QcowMetadata, }; use crate::qcow::qcow_raw_file::QcowRawFile; -use crate::qcow::{MAX_NESTING_DEPTH, RawFile, parse_qcow}; use crate::qcow_common::{ AlignedBuf, aligned_pread, aligned_pwrite, decompress_cluster, gather_from_iovecs, gather_from_iovecs_into, pread_alloc, pread_exact, pwrite_all, scatter_to_iovecs, zero_fill_iovecs, }; -pub struct QcowDiskSync { - metadata: Arc, - /// Shared across queues, resolved once at construction. - backing_file: Option>, - sparse: bool, - data_raw_file: QcowRawFile, -} - -impl fmt::Debug for QcowDiskSync { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("QcowDiskSync") - .field("sparse", &self.sparse) - .field("has_backing", &self.backing_file.is_some()) - .finish_non_exhaustive() - } -} - -impl QcowDiskSync { - pub fn new( - file: File, - direct_io: bool, - backing_files: bool, - sparse: bool, - ) -> BlockResult { - let max_nesting_depth = if backing_files { MAX_NESTING_DEPTH } else { 0 }; - let (inner, backing_file, sparse) = - parse_qcow(RawFile::new(file, direct_io), max_nesting_depth, sparse).map_err(|e| { - let e = if !backing_files && matches!(e.kind(), BlockErrorKind::Overflow) { - e.with_kind(BlockErrorKind::UnsupportedFeature) - } else { - e - }; - e.with_op(ErrorOp::Open) - })?; - let data_raw_file = inner.raw_file.clone(); - Ok(QcowDiskSync { - metadata: Arc::new(QcowMetadata::new(inner)), - backing_file: backing_file.map(shared_backing_from).transpose()?, - sparse, - data_raw_file, - }) - } -} - -impl Drop for QcowDiskSync { - fn drop(&mut self) { - self.metadata.shutdown(); - } -} - -impl disk_file::DiskSize for QcowDiskSync { - fn logical_size(&self) -> BlockResult { - Ok(self.metadata.virtual_size()) - } -} - -impl disk_file::PhysicalSize for QcowDiskSync { - fn physical_size(&self) -> BlockResult { - Ok(self.data_raw_file.physical_size()?) - } -} - -impl disk_file::DiskFd for QcowDiskSync { - fn fd(&self) -> BorrowedDiskFd<'_> { - BorrowedDiskFd::new(self.data_raw_file.as_fd().as_raw_fd()) - } -} - -impl disk_file::Geometry for QcowDiskSync {} - -impl disk_file::SparseCapable for QcowDiskSync { - fn supports_sparse_operations(&self) -> bool { - true - } - - fn supports_zero_flag(&self) -> bool { - true - } -} - -impl disk_file::Resizable for QcowDiskSync { - fn resize(&mut self, size: u64) -> BlockResult<()> { - if self.backing_file.is_some() { - return Err(BlockError::new( - BlockErrorKind::UnsupportedFeature, - DiskFileError::ResizeError(io::Error::other( - "resize not supported with backing file", - )), - ) - .with_op(ErrorOp::Resize)); - } - self.metadata.resize(size).map_err(|e| { - BlockError::new(BlockErrorKind::Io, DiskFileError::ResizeError(e)) - .with_op(ErrorOp::Resize) - }) - } -} - -impl disk_file::DiskFile for QcowDiskSync {} - -impl disk_file::AsyncDiskFile for QcowDiskSync { - fn try_clone(&self) -> BlockResult> { - Ok(Box::new(QcowDiskSync { - metadata: Arc::clone(&self.metadata), - backing_file: self.backing_file.as_ref().map(Arc::clone), - sparse: self.sparse, - data_raw_file: self.data_raw_file.clone(), - })) - } - - // ring_depth is unused - this sync backend performs blocking I/O - // instead of submitting to an async ring. - fn create_async_io(&self, _ring_depth: u32) -> BlockResult> { - Ok(Box::new(QcowSync::new( - Arc::clone(&self.metadata), - self.data_raw_file.clone(), - self.backing_file.as_ref().map(Arc::clone), - self.sparse, - ))) - } -} - pub struct QcowSync { metadata: Arc, data_file: QcowRawFile, - /// See the backing_file field on QcowDiskSync. + /// See the backing_file field on QcowDisk. backing_file: Option>, sparse: bool, /// O_DIRECT alignment requirement (0 = no alignment needed).