From 1ca0c39b4d49c652cdb65ab50a0e1b9f08936d89 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Fri, 24 Apr 2026 23:44:30 +0200 Subject: [PATCH] block: Move VHD format files into formats/vhd/ Move VHD format implementation into a structured directory layout: fixed_vhd.rs -> formats/vhd/internal/fixed.rs (FixedVhd) fixed_vhd_disk.rs -> formats/vhd/mod.rs (VhdDisk) vhd.rs -> formats/vhd/internal/footer.rs (VhdFooter) fixed_vhd_sync.rs -> formats/vhd/worker/sync.rs (FixedVhdSync) fixed_vhd_async.rs -> formats/vhd/worker/async_uring.rs (FixedVhdAsync) Add #[allow(dead_code)] to VhdFooter struct and impl because the module is now pub(crate) and the compiler can see that several fields and getters are only exercised by unit tests. Re-export formats::vhd as fixed_vhd_disk in lib.rs for backward compatibility with external consumers. Signed-off-by: Anatol Belski --- block/src/factory.rs | 2 +- block/src/formats/mod.rs | 1 + .../vhd/internal/fixed.rs} | 2 +- .../{vhd.rs => formats/vhd/internal/footer.rs} | 5 +++++ block/src/formats/vhd/internal/mod.rs | 11 +++++++++++ .../{fixed_vhd_disk.rs => formats/vhd/mod.rs} | 18 ++++++++++++++---- .../vhd/worker/async_uring.rs} | 0 block/src/formats/vhd/worker/mod.rs | 12 ++++++++++++ .../vhd/worker/sync.rs} | 0 block/src/lib.rs | 9 +-------- 10 files changed, 46 insertions(+), 14 deletions(-) rename block/src/{fixed_vhd.rs => formats/vhd/internal/fixed.rs} (98%) rename block/src/{vhd.rs => formats/vhd/internal/footer.rs} (97%) create mode 100644 block/src/formats/vhd/internal/mod.rs rename block/src/{fixed_vhd_disk.rs => formats/vhd/mod.rs} (95%) rename block/src/{fixed_vhd_async.rs => formats/vhd/worker/async_uring.rs} (100%) create mode 100644 block/src/formats/vhd/worker/mod.rs rename block/src/{fixed_vhd_sync.rs => formats/vhd/worker/sync.rs} (100%) diff --git a/block/src/factory.rs b/block/src/factory.rs index a2eee3ae8..d3d50111c 100644 --- a/block/src/factory.rs +++ b/block/src/factory.rs @@ -20,8 +20,8 @@ use log::info; use crate::block_io_uring_is_supported; use crate::disk_file::AsyncFullDiskFile; use crate::error::{BlockError, BlockErrorKind, BlockResult}; -use crate::fixed_vhd_disk::VhdDisk; use crate::formats::raw::{RawBackend, RawDisk}; +use crate::formats::vhd::VhdDisk; use crate::qcow_disk::QcowDisk; use crate::vhdx_sync::VhdxDisk; use crate::{ diff --git a/block/src/formats/mod.rs b/block/src/formats/mod.rs index cf66cd49a..0282640ac 100644 --- a/block/src/formats/mod.rs +++ b/block/src/formats/mod.rs @@ -8,3 +8,4 @@ //! format specific internals, and sync/async I/O workers. pub mod raw; +pub mod vhd; diff --git a/block/src/fixed_vhd.rs b/block/src/formats/vhd/internal/fixed.rs similarity index 98% rename from block/src/fixed_vhd.rs rename to block/src/formats/vhd/internal/fixed.rs index aa9bd9530..9b8b2d682 100644 --- a/block/src/fixed_vhd.rs +++ b/block/src/formats/vhd/internal/fixed.rs @@ -6,8 +6,8 @@ use std::fs::File; use std::io::{Read, Seek, SeekFrom, Write}; use std::os::unix::io::{AsRawFd, RawFd}; +use super::footer::VhdFooter; use crate::BlockBackend; -use crate::vhd::VhdFooter; #[derive(Debug)] pub struct FixedVhd { diff --git a/block/src/vhd.rs b/block/src/formats/vhd/internal/footer.rs similarity index 97% rename from block/src/vhd.rs rename to block/src/formats/vhd/internal/footer.rs index 5a8e59de3..41074631f 100644 --- a/block/src/vhd.rs +++ b/block/src/formats/vhd/internal/footer.rs @@ -7,7 +7,11 @@ use std::io::{Seek, SeekFrom}; use crate::{DiskTopology, read_aligned_block_size}; +// Production code uses: cookie, file_format_version, data_offset, +// current_size, disk_type. The remaining fields are parsed for VHD +// spec completeness and exercised only by unit tests. #[derive(Clone, Copy)] +#[allow(dead_code)] pub struct VhdFooter { cookie: u64, features: u32, @@ -26,6 +30,7 @@ pub struct VhdFooter { saved_state: u8, } +#[allow(dead_code)] impl VhdFooter { pub fn new(file: &mut File) -> std::io::Result { let blocksize = DiskTopology::probe(file)?.logical_block_size as usize; diff --git a/block/src/formats/vhd/internal/mod.rs b/block/src/formats/vhd/internal/mod.rs new file mode 100644 index 000000000..e02ca46f8 --- /dev/null +++ b/block/src/formats/vhd/internal/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +//! VHD format parsing and data structures. +//! +//! Contains the footer parser and the low level fixed VHD +//! block backend. + +pub(crate) mod fixed; +pub(crate) mod footer; diff --git a/block/src/fixed_vhd_disk.rs b/block/src/formats/vhd/mod.rs similarity index 95% rename from block/src/fixed_vhd_disk.rs rename to block/src/formats/vhd/mod.rs index 325b955ae..58f68c2c6 100644 --- a/block/src/fixed_vhd_disk.rs +++ b/block/src/formats/vhd/mod.rs @@ -4,17 +4,27 @@ // // SPDX-License-Identifier: Apache-2.0 +//! Fixed VHD disk image format. +//! +//! Provides [`VhdDisk`], the `DiskFile` wrapper for fixed size VHD +//! images. + +pub(crate) mod internal; +pub(crate) mod worker; + use std::fs::File; use std::io; use std::os::unix::io::AsRawFd; +pub use internal::footer::is_fixed_vhd; + +use self::internal::fixed::FixedVhd; +#[cfg(feature = "io_uring")] +use self::worker::async_uring::FixedVhdAsync; +use self::worker::sync::FixedVhdSync; use crate::async_io::{AsyncIo, BorrowedDiskFd, DiskFileError}; use crate::disk_file::DiskSize; use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; -use crate::fixed_vhd::FixedVhd; -#[cfg(feature = "io_uring")] -use crate::fixed_vhd_async::FixedVhdAsync; -use crate::fixed_vhd_sync::FixedVhdSync; use crate::{BlockBackend, Error, disk_file}; #[derive(Debug)] diff --git a/block/src/fixed_vhd_async.rs b/block/src/formats/vhd/worker/async_uring.rs similarity index 100% rename from block/src/fixed_vhd_async.rs rename to block/src/formats/vhd/worker/async_uring.rs diff --git a/block/src/formats/vhd/worker/mod.rs b/block/src/formats/vhd/worker/mod.rs new file mode 100644 index 000000000..39769731c --- /dev/null +++ b/block/src/formats/vhd/worker/mod.rs @@ -0,0 +1,12 @@ +// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +//! Sync/async I/O workers for fixed VHD images. +//! +//! Thin wrappers around the raw workers that clamp I/O to the +//! virtual disk size. + +#[cfg(feature = "io_uring")] +pub(crate) mod async_uring; +pub(crate) mod sync; diff --git a/block/src/fixed_vhd_sync.rs b/block/src/formats/vhd/worker/sync.rs similarity index 100% rename from block/src/fixed_vhd_sync.rs rename to block/src/formats/vhd/worker/sync.rs diff --git a/block/src/lib.rs b/block/src/lib.rs index ff974a164..99308e8ad 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -14,12 +14,6 @@ pub mod factory; #[path = "io/mod.rs"] mod io_impl; pub use io_impl::{async_io, fcntl, request}; -pub mod fixed_vhd; -#[cfg(feature = "io_uring")] -/// Enabled with the `"io_uring"` feature -pub mod fixed_vhd_async; -pub mod fixed_vhd_disk; -pub mod fixed_vhd_sync; pub mod formats; pub mod qcow; #[cfg(feature = "io_uring")] @@ -29,7 +23,6 @@ pub mod qcow_disk; pub(crate) mod qcow_sync; mod sparse; pub use formats::raw as raw_disk; -pub mod vhd; pub mod vhdx; pub mod vhdx_sync; @@ -521,7 +514,7 @@ pub fn detect_image_type(f: &mut File) -> BlockResult { // Check 4 first bytes to get the header value and determine the image type let image_type = if u32::from_be_bytes(block[0..4].try_into().unwrap()) == QCOW_MAGIC { ImageType::Qcow2 - } else if vhd::is_fixed_vhd(f) + } else if formats::vhd::is_fixed_vhd(f) .map_err(|e| BlockError::new(BlockErrorKind::Io, e).with_op(ErrorOp::DetectImageType))? { ImageType::FixedVhd