From 71203114624fb95be3edff9ceb0f0e5447b3e048 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 7 Jul 2026 18:11:38 +0200 Subject: [PATCH] block: qcow: Flatten internal and worker modules Remove the internal and worker submodule layers from the QCOW2 format directory. The former internal files become direct children of qcow, with internal/mod.rs turning into parser.rs. The worker backends move up as engine_sync.rs and engine_uring.rs, and worker/mod.rs, which held only module declarations, is dropped. The public parser types are now surfaced at the qcow module level, so external callers use block::formats::qcow instead of reaching into the internal module. Assisted-by: Claude:Opus-4.8 Signed-off-by: Anatol Belski --- .../formats/qcow/{internal => }/backing.rs | 4 +- block/src/formats/qcow/common.rs | 8 ++-- .../formats/qcow/{internal => }/decoder.rs | 6 +-- .../qcow/{worker/sync.rs => engine_sync.rs} | 13 +++--- .../async_uring.rs => engine_uring.rs} | 11 +++-- .../src/formats/qcow/{internal => }/header.rs | 3 +- .../formats/qcow/{internal => }/metadata.rs | 24 +++++------ block/src/formats/qcow/mod.rs | 36 ++++++++++------ .../qcow/{internal/mod.rs => parser.rs} | 40 ++++++++---------- .../qcow/{internal => }/qcow_raw_file.rs | 41 +++++++++++-------- .../formats/qcow/{internal => }/refcount.rs | 18 ++++---- block/src/formats/qcow/{internal => }/util.rs | 0 .../formats/qcow/{internal => }/vec_cache.rs | 32 +++++++-------- block/src/formats/qcow/worker/mod.rs | 9 ---- block/src/lib.rs | 2 +- cloud-hypervisor/tests/common/utils.rs | 2 +- performance-metrics/src/util.rs | 3 +- 17 files changed, 125 insertions(+), 127 deletions(-) rename block/src/formats/qcow/{internal => }/backing.rs (97%) rename block/src/formats/qcow/{internal => }/decoder.rs (95%) rename block/src/formats/qcow/{worker/sync.rs => engine_sync.rs} (99%) rename block/src/formats/qcow/{worker/async_uring.rs => engine_uring.rs} (99%) rename block/src/formats/qcow/{internal => }/header.rs (99%) rename block/src/formats/qcow/{internal => }/metadata.rs (98%) rename block/src/formats/qcow/{internal/mod.rs => parser.rs} (99%) rename block/src/formats/qcow/{internal => }/qcow_raw_file.rs (93%) rename block/src/formats/qcow/{internal => }/refcount.rs (95%) rename block/src/formats/qcow/{internal => }/util.rs (100%) rename block/src/formats/qcow/{internal => }/vec_cache.rs (84%) delete mode 100644 block/src/formats/qcow/worker/mod.rs diff --git a/block/src/formats/qcow/internal/backing.rs b/block/src/formats/qcow/backing.rs similarity index 97% rename from block/src/formats/qcow/internal/backing.rs rename to block/src/formats/qcow/backing.rs index ddf73fdd2..ced5cd39b 100644 --- a/block/src/formats/qcow/internal/backing.rs +++ b/block/src/formats/qcow/backing.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use super::decoder::Decoder; use super::metadata::{BackingRead, ClusterReadMapping, QcowMetadata}; -use super::{BackingFile, BackingKind, Error as QcowError}; +use super::parser::{BackingFile, BackingKind, Error as QcowError}; use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; use crate::formats::qcow::common::decompress_cluster; @@ -146,7 +146,7 @@ impl Drop for Qcow2Backing { } /// Construct a thread safe backing file reader. -pub fn shared_backing_from(bf: BackingFile) -> BlockResult> { +pub(super) fn shared_backing_from(bf: BackingFile) -> BlockResult> { let (kind, virtual_size) = bf.into_kind(); let dup_fd = |fd: BorrowedFd<'_>| -> BlockResult { diff --git a/block/src/formats/qcow/common.rs b/block/src/formats/qcow/common.rs index b2e0f3f98..d4f9f25db 100644 --- a/block/src/formats/qcow/common.rs +++ b/block/src/formats/qcow/common.rs @@ -10,16 +10,14 @@ use std::io; -#[cfg(test)] -use super::internal; -use super::internal::decoder::Decoder; +use super::decoder::Decoder; /// Decompress a full QCOW2 cluster from compressed data. /// /// Returns a `cluster_size` byte buffer with the decompressed cluster /// content. Fails if the decoder does not produce exactly `cluster_size` /// bytes. -pub fn decompress_cluster( +pub(super) fn decompress_cluster( compressed: &[u8], cluster_size: usize, decoder: &dyn Decoder, @@ -43,8 +41,8 @@ pub(crate) mod unit_tests { use flate2::Compression; use flate2::write::DeflateEncoder; + use super::super::decoder::ZlibDecoder; use super::decompress_cluster; - use super::internal::decoder::ZlibDecoder; const COMPRESSED_FLAG: u64 = 1 << 62; const CLUSTER_USED_FLAG: u64 = 1 << 63; diff --git a/block/src/formats/qcow/internal/decoder.rs b/block/src/formats/qcow/decoder.rs similarity index 95% rename from block/src/formats/qcow/internal/decoder.rs rename to block/src/formats/qcow/decoder.rs index 537389c30..0e25e6dcb 100644 --- a/block/src/formats/qcow/internal/decoder.rs +++ b/block/src/formats/qcow/decoder.rs @@ -18,7 +18,7 @@ pub enum Error { ZstdFillBuffer(#[source] io::Error), } -pub type Result = result::Result; +pub(super) type Result = result::Result; /// Generic trait for decoding zlib/zstd formats pub trait Decoder: Send + Sync { @@ -26,7 +26,7 @@ pub trait Decoder: Send + Sync { } #[derive(Default)] -pub struct ZlibDecoder {} +pub(super) struct ZlibDecoder {} impl Decoder for ZlibDecoder { fn decode(&self, input: &[u8], output: &mut [u8]) -> Result { @@ -45,7 +45,7 @@ impl Decoder for ZlibDecoder { } #[derive(Default)] -pub struct ZstdDecoder {} +pub(super) struct ZstdDecoder {} impl Decoder for ZstdDecoder { fn decode(&self, input: &[u8], output: &mut [u8]) -> Result { diff --git a/block/src/formats/qcow/worker/sync.rs b/block/src/formats/qcow/engine_sync.rs similarity index 99% rename from block/src/formats/qcow/worker/sync.rs rename to block/src/formats/qcow/engine_sync.rs index 9456bddf2..f02c6c43f 100644 --- a/block/src/formats/qcow/worker/sync.rs +++ b/block/src/formats/qcow/engine_sync.rs @@ -13,14 +13,14 @@ use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt}; use super::common::decompress_cluster; -use super::internal::decoder::Decoder; -use super::internal::metadata::{ +use super::decoder::Decoder; +use super::metadata::{ BackingRead, ClusterReadMapping, ClusterWriteMapping, DeallocAction, QcowMetadata, }; -use super::internal::qcow_raw_file::QcowRawFile; +use super::qcow_raw_file::QcowRawFile; use crate::async_io::{AsyncIo, AsyncIoCompletion, AsyncIoError, AsyncIoOperation, AsyncIoResult}; -pub struct QcowSync { +pub(super) struct QcowSync { metadata: Arc, data_file: QcowRawFile, /// See the backing_file field on QcowDisk. @@ -322,10 +322,9 @@ mod unit_tests { use crate::error::BlockErrorKind; use crate::formats::qcow; use crate::formats::qcow::common::unit_tests::compress_allocated_clusters; - use crate::formats::qcow::internal::{ - BackingFileConfig, Error as QcowError, ImageType, QcowHeader, + use crate::formats::qcow::{ + BackingFileConfig, Error as QcowError, ImageType, QcowDisk, QcowHeader, QcowTempDisk, }; - use crate::formats::qcow::{QcowDisk, QcowTempDisk}; const TEST_L1_L2_ADDR_MASK: u64 = 0x00ff_ffff_ffff_fe00; const TEST_HEADER_L1_TABLE_OFFSET: u64 = 40; diff --git a/block/src/formats/qcow/worker/async_uring.rs b/block/src/formats/qcow/engine_uring.rs similarity index 99% rename from block/src/formats/qcow/worker/async_uring.rs rename to block/src/formats/qcow/engine_uring.rs index 24dab966d..7999dab23 100644 --- a/block/src/formats/qcow/worker/async_uring.rs +++ b/block/src/formats/qcow/engine_uring.rs @@ -18,11 +18,11 @@ use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt}; use super::common::decompress_cluster; -use super::internal::decoder::Decoder; -use super::internal::metadata::{ +use super::decoder::Decoder; +use super::metadata::{ BackingRead, ClusterReadMapping, ClusterWriteMapping, DeallocAction, QcowMetadata, }; -use super::internal::qcow_raw_file::QcowRawFile; +use super::qcow_raw_file::QcowRawFile; use crate::async_io::{ AsyncIo, AsyncIoCompletion, AsyncIoError, AsyncIoOperation, AsyncIoResult, UringDataIo, }; @@ -36,7 +36,7 @@ use crate::async_io::{ /// /// Writes are synchronous because metadata allocation must complete /// before the host offset is known. -pub struct QcowAsync { +pub(super) struct QcowAsync { metadata: Arc, // Drop before data_file so pending SQEs can be submitted while fd is valid. data_io: UringDataIo, @@ -483,8 +483,7 @@ mod unit_tests { use crate::async_io::{AsyncIoCompletion, AsyncIoOperation, GuestMemoryTarget, OwnedIoBuffer}; use crate::disk_file::AsyncDiskFile; use crate::formats::qcow::common::unit_tests::compress_allocated_clusters; - use crate::formats::qcow::internal::{BackingFileConfig, ImageType}; - use crate::formats::qcow::{QcowDisk, QcowTempDisk}; + use crate::formats::qcow::{BackingFileConfig, ImageType, QcowDisk, QcowTempDisk}; fn create_disk_with_data( file_size: u64, diff --git a/block/src/formats/qcow/internal/header.rs b/block/src/formats/qcow/header.rs similarity index 99% rename from block/src/formats/qcow/internal/header.rs rename to block/src/formats/qcow/header.rs index f4b677788..e8e1fe846 100644 --- a/block/src/formats/qcow/internal/header.rs +++ b/block/src/formats/qcow/header.rs @@ -16,8 +16,9 @@ use bitflags::bitflags; use vmm_sys_util::file_traits::FileSync; use super::decoder::{Decoder, ZlibDecoder, ZstdDecoder}; +use super::parser::{Error, Result}; use super::qcow_raw_file::BeUint; -use super::{Error, Result, div_round_up_u32, div_round_up_u64}; +use super::util::{div_round_up_u32, div_round_up_u64}; use crate::aligned_file::AlignedFile; use crate::error::{BlockError, BlockErrorKind, BlockResult}; diff --git a/block/src/formats/qcow/internal/metadata.rs b/block/src/formats/qcow/metadata.rs similarity index 98% rename from block/src/formats/qcow/internal/metadata.rs rename to block/src/formats/qcow/metadata.rs index 42f1b96b0..aa477f1d9 100644 --- a/block/src/formats/qcow/internal/metadata.rs +++ b/block/src/formats/qcow/metadata.rs @@ -41,7 +41,7 @@ use super::{QcowHeader, refcount}; /// the actual data I/O using its own per queue file descriptor without /// holding the metadata lock. #[derive(Debug)] -pub enum ClusterReadMapping { +pub(super) enum ClusterReadMapping { /// The cluster is not allocated and the guest should see zeros. /// This covers both truly unallocated clusters where the L1 or L2 /// entry is zero and clusters with the ZERO flag set. @@ -76,7 +76,7 @@ pub enum ClusterReadMapping { /// the actual data I/O using its own per queue file descriptor without /// holding the metadata lock. #[derive(Debug)] -pub enum ClusterWriteMapping { +pub(super) enum ClusterWriteMapping { /// The write target is at the given host file offset. /// This covers both already allocated clusters and freshly allocated ones. /// The offset is the exact byte position combining cluster base and @@ -94,7 +94,7 @@ pub(crate) trait BackingRead: Send + Sync { /// Action that the caller must perform after deallocate_bytes. #[derive(Debug)] -pub enum DeallocAction { +pub(super) enum DeallocAction { /// Punch a hole at the given host file offset for a full cluster. PunchHole { host_offset: u64, length: u64 }, /// Write zeros at the given host file offset for a partial cluster. @@ -115,7 +115,7 @@ pub enum DeallocAction { /// L1 to L2 lookup, which completes under a shared read lock. Only /// cluster allocation, L2 cache eviction and resize take the exclusive /// write lock, so contention stays low and queues scale. -pub struct QcowMetadata { +pub(super) struct QcowMetadata { inner: RwLock, decoder: Arc, } @@ -160,7 +160,7 @@ impl QcowMetadata { /// /// The has_backing_file flag indicates whether a backing file exists, /// needed to distinguish zero versus backing for unallocated clusters. - pub fn map_clusters_for_read( + pub(super) fn map_clusters_for_read( &self, address: u64, total_length: usize, @@ -228,7 +228,7 @@ impl QcowMetadata { /// unallocated and a backing file exists, the caller should have already /// read the backing cluster data and pass it here. If None, the new /// cluster is zeroed. - pub fn map_cluster_for_write( + pub(super) fn map_cluster_for_write( &self, address: u64, backing_data: Option>, @@ -237,7 +237,7 @@ impl QcowMetadata { inner.map_write(address, backing_data) } - pub fn flush(&self) -> io::Result<()> { + pub(super) fn flush(&self) -> io::Result<()> { let mut inner = self.inner.write().unwrap(); inner.sync_caches()?; let mut unref = mem::take(&mut inner.unref_clusters); @@ -247,7 +247,7 @@ impl QcowMetadata { /// Flushes dirty metadata caches and clears the dirty bit for /// clean shutdown. - pub fn shutdown(&self) { + pub(super) fn shutdown(&self) { let mut inner = self.inner.write().unwrap(); let _ = inner.sync_caches(); let QcowState { @@ -265,7 +265,7 @@ impl QcowMetadata { /// clusters beyond the new size and risks data loss. /// /// Returns an error if the new size is smaller than the current size. - pub fn resize(&self, new_size: u64) -> io::Result<()> { + pub(super) fn resize(&self, new_size: u64) -> io::Result<()> { let mut inner = self.inner.write().unwrap(); inner.resize(new_size) } @@ -339,16 +339,16 @@ impl QcowMetadata { Ok(actions) } - pub fn virtual_size(&self) -> u64 { + pub(super) fn virtual_size(&self) -> u64 { self.inner.read().unwrap().header.size } - pub fn cluster_size(&self) -> u64 { + pub(super) fn cluster_size(&self) -> u64 { self.inner.read().unwrap().raw_file.cluster_size() } /// Returns the shared decoder matching the image compression type. - pub fn decoder(&self) -> Arc { + pub(super) fn decoder(&self) -> Arc { Arc::clone(&self.decoder) } diff --git a/block/src/formats/qcow/mod.rs b/block/src/formats/qcow/mod.rs index 650411cca..f3b5950f9 100644 --- a/block/src/formats/qcow/mod.rs +++ b/block/src/formats/qcow/mod.rs @@ -7,9 +7,19 @@ //! Provides [`QcowDisk`], the `DiskFile` wrapper for QCOW2 images //! with backing file and compression support. -pub(crate) mod common; -pub mod internal; -pub mod worker; +mod backing; +mod common; +mod decoder; +mod engine_sync; +#[cfg(feature = "io_uring")] +mod engine_uring; +mod header; +mod metadata; +mod parser; +mod qcow_raw_file; +mod refcount; +mod util; +mod vec_cache; use std::fs::File; use std::os::unix::io::AsRawFd; @@ -18,20 +28,22 @@ use std::path::Path; use std::sync::Arc; use std::{fmt, io}; +pub use parser::{ + BackingFileConfig, CompressionType, Error, ImageType, IncompatFeatures, MissingFeatureError, + QcowHeader, +}; #[cfg(any(test, feature = "test-utils"))] use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap}; #[cfg(any(test, feature = "test-utils"))] use vmm_sys_util::tempfile::TempFile; -use self::internal::backing::shared_backing_from; -use self::internal::metadata::{BackingRead, QcowMetadata}; -use self::internal::qcow_raw_file::QcowRawFile; -#[cfg(any(test, feature = "test-utils"))] -use self::internal::{BackingFileConfig, QcowHeader}; -use self::internal::{MAX_NESTING_DEPTH, parse_qcow}; +use self::backing::shared_backing_from; +use self::engine_sync::QcowSync; #[cfg(feature = "io_uring")] -use self::worker::async_uring::QcowAsync; -use self::worker::sync::QcowSync; +use self::engine_uring::QcowAsync; +use self::metadata::{BackingRead, QcowMetadata}; +use self::parser::{MAX_NESTING_DEPTH, parse_qcow}; +use self::qcow_raw_file::QcowRawFile; use crate::aligned_file::AlignedFile; #[cfg(any(test, feature = "test-utils"))] use crate::async_io::GuestMemoryTarget; @@ -142,7 +154,7 @@ impl QcowDisk { } #[cfg(test)] - pub(crate) fn metadata(&self) -> &QcowMetadata { + fn metadata(&self) -> &QcowMetadata { &self.metadata } } diff --git a/block/src/formats/qcow/internal/mod.rs b/block/src/formats/qcow/parser.rs similarity index 99% rename from block/src/formats/qcow/internal/mod.rs rename to block/src/formats/qcow/parser.rs index 55d68fe91..cfffa42e1 100644 --- a/block/src/formats/qcow/internal/mod.rs +++ b/block/src/formats/qcow/parser.rs @@ -4,15 +4,6 @@ // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause -pub(crate) mod backing; -pub(crate) mod decoder; -mod header; -pub(crate) mod metadata; -pub(crate) mod qcow_raw_file; -mod refcount; -mod util; -mod vec_cache; - use std::cmp::{max, min}; use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::fs::{OpenOptions, read_link}; @@ -21,24 +12,25 @@ use std::os::unix::fs::FileExt; use std::path::Path; use std::{io, result, str}; -pub use header::{ +use log::warn; +use remain::sorted; +use thiserror::Error; + +pub use super::header::{ BackingFileConfig, CompressionType, ImageType, IncompatFeatures, MissingFeatureError, QcowHeader, }; -use header::{ +use super::header::{ COMPATIBLE_FEATURES_LAZY_REFCOUNTS, MAX_CLUSTER_BITS, MAX_QCOW_FILE_SIZE, MAX_RAM_POINTER_TABLE_SIZE, MIN_CLUSTER_BITS, QCOW_MAGIC, max_refcount_clusters, offset_is_cluster_boundary, }; -use log::warn; -use qcow_raw_file::QcowRawFile; -use refcount::RefCount; -use remain::sorted; -use thiserror::Error; -pub(crate) use util::MAX_NESTING_DEPTH; -use util::{L1_TABLE_OFFSET_MASK, L2_TABLE_OFFSET_MASK, div_round_up_u32, div_round_up_u64}; -use vec_cache::{CacheMap, VecCache}; - +use super::qcow_raw_file::QcowRawFile; +use super::refcount::RefCount; +pub(crate) use super::util::MAX_NESTING_DEPTH; +use super::util::{L1_TABLE_OFFSET_MASK, L2_TABLE_OFFSET_MASK, div_round_up_u64}; +use super::vec_cache::{CacheMap, VecCache}; +use super::{metadata, refcount}; use crate::aligned_file::AlignedFile; use crate::error::{BlockError, BlockErrorKind, BlockResult}; use crate::query_device_size; @@ -156,7 +148,7 @@ pub enum Error { WritingHeader(#[source] io::Error), } -pub type Result = result::Result; +pub(super) type Result = result::Result; /// Concrete backing file variants. pub(crate) enum BackingKind { @@ -865,7 +857,7 @@ fn rebuild_refcounts(raw_file: &mut QcowRawFile, header: QcowHeader) -> BlockRes } /// Detect the type of an image file by checking for a valid qcow2 header. -pub fn detect_image_type(file: &mut AlignedFile) -> BlockResult { +pub(super) fn detect_image_type(file: &mut AlignedFile) -> BlockResult { let mut magic_bytes = [0u8; 4]; file.read_exact_at(&mut magic_bytes, 0) .map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?; @@ -888,11 +880,11 @@ mod unit_tests { use vmm_sys_util::tempdir::TempDir; use vmm_sys_util::tempfile::TempFile; - use super::header::{ + use super::super::header::{ AUTOCLEAR_FEATURES_OFFSET, DEFAULT_CLUSTER_BITS, DEFAULT_REFCOUNT_ORDER, HEADER_EXT_BACKING_FORMAT, HEADER_EXT_END, V2_BARE_HEADER_SIZE, V3_BARE_HEADER_SIZE, }; - use super::util::ZERO_FLAG; + use super::super::util::{self, ZERO_FLAG}; use super::*; use crate::formats::qcow::{QcowDisk, QcowTempDisk}; diff --git a/block/src/formats/qcow/internal/qcow_raw_file.rs b/block/src/formats/qcow/qcow_raw_file.rs similarity index 93% rename from block/src/formats/qcow/internal/qcow_raw_file.rs rename to block/src/formats/qcow/qcow_raw_file.rs index d1814c5e3..6bd7f541a 100644 --- a/block/src/formats/qcow/internal/qcow_raw_file.rs +++ b/block/src/formats/qcow/qcow_raw_file.rs @@ -149,7 +149,7 @@ fn write_refcount_subbyte( /// A qcow file. Allows reading/writing clusters and appending clusters. #[derive(Debug)] -pub struct QcowRawFile { +pub(super) struct QcowRawFile { file: AlignedFile, cluster_size: u64, cluster_mask: u64, @@ -161,7 +161,7 @@ pub struct QcowRawFile { impl QcowRawFile { /// Creates a `QcowRawFile` from the given `File`, `None` is returned if `cluster_size` is not /// a power of two or refcount_bits is invalid. - pub fn from(file: AlignedFile, cluster_size: u64, refcount_bits: u64) -> Option { + pub(super) fn from(file: AlignedFile, cluster_size: u64, refcount_bits: u64) -> Option { if !cluster_size.is_power_of_two() { return None; } @@ -193,7 +193,7 @@ impl QcowRawFile { /// Reads `count` 64 bit offsets and returns them as a vector. /// `mask` optionally `&`s out some of the bits on the file. - pub fn read_pointer_table( + pub(super) fn read_pointer_table( &mut self, offset: u64, count: u64, @@ -213,7 +213,11 @@ impl QcowRawFile { /// Reads a cluster's worth of 64 bit offsets and returns them as a vector. /// `mask` optionally `&`s out some of the bits on the file. - pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option) -> io::Result> { + pub(super) fn read_pointer_cluster( + &mut self, + offset: u64, + mask: Option, + ) -> io::Result> { let count = self.cluster_size / size_of::() as u64; self.read_pointer_table(offset, count, mask) } @@ -223,7 +227,7 @@ impl QcowRawFile { /// /// The callback may perform metadata I/O on this `QcowRawFile`, so all /// entries are materialized before the final positional write. - pub fn write_pointer_table<'a, T: Copy + 'a>( + pub(super) fn write_pointer_table<'a, T: Copy + 'a>( &mut self, offset: u64, entries: impl Iterator, @@ -240,7 +244,7 @@ impl QcowRawFile { /// Writes a pointer table directly without transforming values. /// /// Uses the same materialize-then-write path as `write_pointer_table`. - pub fn write_pointer_table_direct<'a>( + pub(super) fn write_pointer_table_direct<'a>( &mut self, offset: u64, entries: impl Iterator, @@ -255,18 +259,21 @@ impl QcowRawFile { /// Read a refcount block from the file and returns a Vec containing the block. /// Always returns a cluster's worth of data. #[inline] - pub fn read_refcount_block(&mut self, offset: u64) -> io::Result> { + pub(super) fn read_refcount_block(&mut self, offset: u64) -> io::Result> { (self.read_refcount_fn)(&mut self.file, offset, self.refcount_block_entries as usize) } /// Writes a refcount block to the file. #[inline] - pub fn write_refcount_block(&mut self, offset: u64, table: &[u64]) -> io::Result<()> { + pub(super) fn write_refcount_block(&mut self, offset: u64, table: &[u64]) -> io::Result<()> { (self.write_refcount_fn)(&mut self.file, offset, table) } /// Allocates a new cluster at the end of the current file, return the address. - pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result> { + pub(super) fn add_cluster_end( + &mut self, + max_valid_cluster_offset: u64, + ) -> io::Result> { // Determine where the new end of the file should be and set_len, which // translates to truncate(2). let file_end: u64 = self.physical_size()?; @@ -282,44 +289,44 @@ impl QcowRawFile { } /// Returns a reference to the underlying file. - pub fn file(&self) -> &AlignedFile { + pub(super) fn file(&self) -> &AlignedFile { &self.file } /// Returns a mutable reference to the underlying file. - pub fn file_mut(&mut self) -> &mut AlignedFile { + pub(super) fn file_mut(&mut self) -> &mut AlignedFile { &mut self.file } /// Returns the size of the file's clusters. - pub fn cluster_size(&self) -> u64 { + pub(super) fn cluster_size(&self) -> u64 { self.cluster_size } /// Returns the offset of `address` within a cluster. - pub fn cluster_offset(&self, address: u64) -> u64 { + pub(super) fn cluster_offset(&self, address: u64) -> u64 { address & self.cluster_mask } /// Returns the base address of the cluster containing `address`. - pub fn cluster_address(&self, address: u64) -> u64 { + pub(super) fn cluster_address(&self, address: u64) -> u64 { address & !self.cluster_mask } /// Zeros out a cluster in the file. - pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> { + pub(super) fn zero_cluster(&mut self, address: u64) -> io::Result<()> { let cluster_size = self.cluster_size as usize; self.file.write_all_zeroes_at(address, cluster_size)?; Ok(()) } /// Writes - pub fn write_cluster(&mut self, address: u64, data: &[u8]) -> io::Result<()> { + pub(super) fn write_cluster(&mut self, address: u64, data: &[u8]) -> io::Result<()> { let cluster_size = self.cluster_size as usize; self.file.write_all_at(&data[0..cluster_size], address) } - pub fn physical_size(&self) -> io::Result { + pub(super) fn physical_size(&self) -> io::Result { self.file.metadata().map(|m| m.len()) } } diff --git a/block/src/formats/qcow/internal/refcount.rs b/block/src/formats/qcow/refcount.rs similarity index 95% rename from block/src/formats/qcow/internal/refcount.rs rename to block/src/formats/qcow/refcount.rs index 77beac7d0..3d335f881 100644 --- a/block/src/formats/qcow/internal/refcount.rs +++ b/block/src/formats/qcow/refcount.rs @@ -41,11 +41,11 @@ pub enum Error { }, } -pub type Result = result::Result; +pub(super) type Result = result::Result; /// Represents the refcount entries for an open qcow file. #[derive(Clone, Debug)] -pub struct RefCount { +pub(super) struct RefCount { ref_table: VecCache, refcount_table_offset: u64, refblock_cache: CacheMap>, @@ -62,7 +62,7 @@ impl RefCount { /// `refcount_block_entries` indicates the number of refcounts in each refcount block. /// `refcount_bits` is the number of bits per refcount (1, 2, 4, 8, 16, 32, or 64). /// Each refcount table entry points to a refcount block. - pub fn new( + pub(super) fn new( raw_file: &mut QcowRawFile, refcount_table_offset: u64, refcount_table_entries: u64, @@ -95,12 +95,12 @@ impl RefCount { } /// Returns the number of refcounts per block. - pub fn refcounts_per_block(&self) -> u64 { + pub(super) fn refcounts_per_block(&self) -> u64 { self.refcount_block_entries } /// Returns the maximum valid cluster offset in the raw file for this refcount table. - pub fn max_valid_cluster_offset(&self) -> u64 { + pub(super) fn max_valid_cluster_offset(&self) -> u64 { self.max_valid_cluster_offset } @@ -109,7 +109,7 @@ impl RefCount { /// allocate a cluster or read the required one and call this function again with the cluster. /// On success, an optional address of a dropped cluster is returned. The dropped cluster can /// be reused for other purposes. - pub fn set_cluster_refcount( + pub(super) fn set_cluster_refcount( &mut self, raw_file: &mut QcowRawFile, cluster_address: u64, @@ -167,7 +167,7 @@ impl RefCount { /// Flush the dirty refcount blocks. This must be done before flushing the table that points to /// the blocks. - pub fn flush_blocks(&mut self, raw_file: &mut QcowRawFile) -> io::Result<()> { + pub(super) fn flush_blocks(&mut self, raw_file: &mut QcowRawFile) -> io::Result<()> { // Write out all dirty L2 tables. for (table_index, block) in self.refblock_cache.iter_mut().filter(|(_k, v)| v.dirty()) { let addr = self.ref_table[*table_index]; @@ -183,7 +183,7 @@ impl RefCount { /// Flush the refcount table that keeps the address of the refcounts blocks. /// Returns true if the table changed since the previous `flush_table()` call. - pub fn flush_table(&mut self, raw_file: &mut QcowRawFile) -> io::Result { + pub(super) fn flush_table(&mut self, raw_file: &mut QcowRawFile) -> io::Result { if self.ref_table.dirty() { raw_file .write_pointer_table_direct(self.refcount_table_offset, self.ref_table.iter())?; @@ -195,7 +195,7 @@ impl RefCount { } /// Gets the refcount for a cluster with the given address. - pub fn get_cluster_refcount( + pub(super) fn get_cluster_refcount( &mut self, raw_file: &mut QcowRawFile, address: u64, diff --git a/block/src/formats/qcow/internal/util.rs b/block/src/formats/qcow/util.rs similarity index 100% rename from block/src/formats/qcow/internal/util.rs rename to block/src/formats/qcow/util.rs diff --git a/block/src/formats/qcow/internal/vec_cache.rs b/block/src/formats/qcow/vec_cache.rs similarity index 84% rename from block/src/formats/qcow/internal/vec_cache.rs rename to block/src/formats/qcow/vec_cache.rs index 064642187..acbf145bc 100644 --- a/block/src/formats/qcow/internal/vec_cache.rs +++ b/block/src/formats/qcow/vec_cache.rs @@ -12,21 +12,21 @@ use std::slice::SliceIndex; /// Trait that allows for checking if an implementor is dirty. Useful for types that are cached so /// it can be checked if they need to be committed to disk. -pub trait Cacheable { +pub(super) trait Cacheable { /// Used to check if the item needs to be written out or if it can be discarded. fn dirty(&self) -> bool; } #[derive(Clone, Debug)] /// Represents a vector that implements the `Cacheable` trait so it can be held in a cache. -pub struct VecCache { +pub(super) struct VecCache { vec: Box<[T]>, dirty: bool, } impl VecCache { /// Creates a `VecCache` that can hold `count` elements. - pub fn new(count: usize) -> VecCache { + pub(super) fn new(count: usize) -> VecCache { VecCache { vec: vec![Default::default(); count].into_boxed_slice(), dirty: true, @@ -34,14 +34,14 @@ impl VecCache { } /// Creates a `VecCache` from the passed in `vec`. - pub fn from_vec(vec: Vec) -> VecCache { + pub(super) fn from_vec(vec: Vec) -> VecCache { VecCache { vec: vec.into_boxed_slice(), dirty: false, } } - pub fn get(&self, index: I) -> Option<&>::Output> + pub(super) fn get(&self, index: I) -> Option<&>::Output> where I: SliceIndex<[T]>, { @@ -49,17 +49,17 @@ impl VecCache { } /// Gets a reference to the underlying vector. - pub fn get_values(&self) -> &[T] { + pub(super) fn get_values(&self) -> &[T] { &self.vec } /// Mark this cache element as clean. - pub fn mark_clean(&mut self) { + pub(super) fn mark_clean(&mut self) { self.dirty = false; } /// Returns the number of elements in the vector. - pub fn len(&self) -> usize { + pub(super) fn len(&self) -> usize { self.vec.len() } @@ -68,7 +68,7 @@ impl VecCache { /// No-op if `new_len <= self.len()`. Allocates a new buffer, copies /// existing data, and fills new elements with default values. /// Marks the cache as dirty. - pub fn extend(&mut self, new_len: usize) { + pub(super) fn extend(&mut self, new_len: usize) { if new_len <= self.vec.len() { return; } @@ -109,37 +109,37 @@ impl Deref for VecCache { } #[derive(Clone, Debug)] -pub struct CacheMap { +pub(super) struct CacheMap { capacity: usize, map: HashMap, } impl CacheMap { - pub fn new(capacity: usize) -> Self { + pub(super) fn new(capacity: usize) -> Self { CacheMap { capacity, map: HashMap::with_capacity(capacity), } } - pub fn contains_key(&self, key: usize) -> bool { + pub(super) fn contains_key(&self, key: usize) -> bool { self.map.contains_key(&key) } - pub fn get(&self, index: usize) -> Option<&T> { + pub(super) fn get(&self, index: usize) -> Option<&T> { self.map.get(&index) } - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + pub(super) fn get_mut(&mut self, index: usize) -> Option<&mut T> { self.map.get_mut(&index) } - pub fn iter_mut(&mut self) -> IterMut<'_, usize, T> { + pub(super) fn iter_mut(&mut self) -> IterMut<'_, usize, T> { self.map.iter_mut() } // Check if the refblock cache is full and we need to evict. - pub fn insert(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()> + pub(super) fn insert(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()> where F: FnOnce(usize, T) -> io::Result<()>, { diff --git a/block/src/formats/qcow/worker/mod.rs b/block/src/formats/qcow/worker/mod.rs deleted file mode 100644 index 6da78e821..000000000 --- a/block/src/formats/qcow/worker/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved. -// -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(feature = "io_uring")] -pub(crate) mod async_uring; -pub(crate) mod sync; - -pub(crate) use super::{common, internal}; diff --git a/block/src/lib.rs b/block/src/lib.rs index 6fd2d544a..d8c5600b8 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -28,7 +28,7 @@ use std::str::FromStr; use std::{cmp, io, mem, result}; pub use aligned_file::AlignedFile; -use formats::qcow::internal as qcow; +use formats::qcow; #[cfg(feature = "io_uring")] use io_uring::{IoUring, Probe, opcode}; use libc::{ diff --git a/cloud-hypervisor/tests/common/utils.rs b/cloud-hypervisor/tests/common/utils.rs index 7a6d1c6ed..22c982dc0 100644 --- a/cloud-hypervisor/tests/common/utils.rs +++ b/cloud-hypervisor/tests/common/utils.rs @@ -14,7 +14,7 @@ use std::sync::mpsc::Receiver; use std::time::{Duration, Instant}; use std::{cmp, fs, io, panic, thread}; -use block::formats::qcow::internal::ImageType as QcowImageType; +use block::formats::qcow::ImageType as QcowImageType; use test_infra::*; use vmm_sys_util::tempdir::TempDir; #[cfg(not(feature = "mshv"))] diff --git a/performance-metrics/src/util.rs b/performance-metrics/src/util.rs index 66262d690..5139e9ac2 100644 --- a/performance-metrics/src/util.rs +++ b/performance-metrics/src/util.rs @@ -15,8 +15,7 @@ use std::thread; use std::time::Duration; use block::async_io::{AsyncIo, GuestMemoryTarget}; -use block::formats::qcow::internal::{BackingFileConfig, ImageType}; -use block::formats::qcow::{QcowDisk, QcowTempDisk}; +use block::formats::qcow::{BackingFileConfig, ImageType, QcowDisk, QcowTempDisk}; use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::tempfile::TempFile;