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 <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-07-07 18:11:38 +02:00
committed by Rob Bradford
parent b5aeabe77c
commit 7120311462
17 changed files with 125 additions and 127 deletions

View File

@@ -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<Arc<dyn BackingRead>> {
pub(super) fn shared_backing_from(bf: BackingFile) -> BlockResult<Arc<dyn BackingRead>> {
let (kind, virtual_size) = bf.into_kind();
let dup_fd = |fd: BorrowedFd<'_>| -> BlockResult<OwnedFd> {

View File

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

View File

@@ -18,7 +18,7 @@ pub enum Error {
ZstdFillBuffer(#[source] io::Error),
}
pub type Result<T> = result::Result<T, Error>;
pub(super) type Result<T> = result::Result<T, Error>;
/// 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<usize> {
@@ -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<usize> {

View File

@@ -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<QcowMetadata>,
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;

View File

@@ -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<QcowMetadata>,
// 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,

View File

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

View File

@@ -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<QcowState>,
decoder: Arc<dyn Decoder>,
}
@@ -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<Vec<u8>>,
@@ -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<dyn Decoder> {
pub(super) fn decoder(&self) -> Arc<dyn Decoder> {
Arc::clone(&self.decoder)
}

View File

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

View File

@@ -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<T> = result::Result<T, Error>;
pub(super) type Result<T> = result::Result<T, Error>;
/// 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<ImageType> {
pub(super) fn detect_image_type(file: &mut AlignedFile) -> BlockResult<ImageType> {
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};

View File

@@ -149,7 +149,7 @@ fn write_refcount_subbyte<const BITS: usize>(
/// 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<Self> {
pub(super) fn from(file: AlignedFile, cluster_size: u64, refcount_bits: u64) -> Option<Self> {
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<u64>) -> io::Result<Vec<u64>> {
pub(super) fn read_pointer_cluster(
&mut self,
offset: u64,
mask: Option<u64>,
) -> io::Result<Vec<u64>> {
let count = self.cluster_size / size_of::<u64>() 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<Item = &'a T>,
@@ -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<Item = &'a u64>,
@@ -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<Vec<u64>> {
pub(super) fn read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u64>> {
(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<Option<u64>> {
pub(super) fn add_cluster_end(
&mut self,
max_valid_cluster_offset: u64,
) -> io::Result<Option<u64>> {
// 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<u64> {
pub(super) fn physical_size(&self) -> io::Result<u64> {
self.file.metadata().map(|m| m.len())
}
}

View File

@@ -41,11 +41,11 @@ pub enum Error {
},
}
pub type Result<T> = result::Result<T, Error>;
pub(super) type Result<T> = result::Result<T, Error>;
/// Represents the refcount entries for an open qcow file.
#[derive(Clone, Debug)]
pub struct RefCount {
pub(super) struct RefCount {
ref_table: VecCache<u64>,
refcount_table_offset: u64,
refblock_cache: CacheMap<VecCache<u64>>,
@@ -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<bool> {
pub(super) fn flush_table(&mut self, raw_file: &mut QcowRawFile) -> io::Result<bool> {
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,

View File

@@ -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<T: 'static + Copy + Default> {
pub(super) struct VecCache<T: 'static + Copy + Default> {
vec: Box<[T]>,
dirty: bool,
}
impl<T: 'static + Copy + Default> VecCache<T> {
/// Creates a `VecCache` that can hold `count` elements.
pub fn new(count: usize) -> VecCache<T> {
pub(super) fn new(count: usize) -> VecCache<T> {
VecCache {
vec: vec![Default::default(); count].into_boxed_slice(),
dirty: true,
@@ -34,14 +34,14 @@ impl<T: 'static + Copy + Default> VecCache<T> {
}
/// Creates a `VecCache` from the passed in `vec`.
pub fn from_vec(vec: Vec<T>) -> VecCache<T> {
pub(super) fn from_vec(vec: Vec<T>) -> VecCache<T> {
VecCache {
vec: vec.into_boxed_slice(),
dirty: false,
}
}
pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
pub(super) fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
where
I: SliceIndex<[T]>,
{
@@ -49,17 +49,17 @@ impl<T: 'static + Copy + Default> VecCache<T> {
}
/// 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<T: 'static + Copy + Default> VecCache<T> {
/// 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<T: 'static + Copy + Default> Deref for VecCache<T> {
}
#[derive(Clone, Debug)]
pub struct CacheMap<T: Cacheable> {
pub(super) struct CacheMap<T: Cacheable> {
capacity: usize,
map: HashMap<usize, T>,
}
impl<T: Cacheable> CacheMap<T> {
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<F>(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()>
pub(super) fn insert<F>(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()>
where
F: FnOnce(usize, T) -> io::Result<()>,
{

View File

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

View File

@@ -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::{

View File

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

View File

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