From 039b4e6013d6d75b5f5f4c1fb79895a50444f39d Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 7 Jul 2026 23:14:33 +0200 Subject: [PATCH] block: vhdx: Flatten internal and worker modules Remove the internal and worker submodule layers from the VHDX format directory. The bat, header, io, and metadata parsers move up as direct children, internal/mod.rs becomes parser.rs, and the sync backend moves up as engine_sync.rs. The declaration only worker/mod.rs is dropped. The public types are surfaced at the vhdx module level, so callers use block::formats::vhdx instead of reaching into the internal module. Assisted-by: Claude:Opus-4.8 Signed-off-by: Anatol Belski --- block/src/formats/vhdx/{internal => }/bat.rs | 24 ++++++++-------- .../vhdx/{worker/sync.rs => engine_sync.rs} | 8 +++--- .../src/formats/vhdx/{internal => }/header.rs | 28 +++++++++---------- block/src/formats/vhdx/{internal => }/io.rs | 8 +++--- .../formats/vhdx/{internal => }/metadata.rs | 12 ++++---- block/src/formats/vhdx/mod.rs | 18 +++++++----- .../vhdx/{internal/mod.rs => parser.rs} | 15 ++++------ block/src/formats/vhdx/worker/mod.rs | 7 ----- 8 files changed, 56 insertions(+), 64 deletions(-) rename block/src/formats/vhdx/{internal => }/bat.rs (82%) rename block/src/formats/vhdx/{worker/sync.rs => engine_sync.rs} (97%) rename block/src/formats/vhdx/{internal => }/header.rs (96%) rename block/src/formats/vhdx/{internal => }/io.rs (98%) rename block/src/formats/vhdx/{internal => }/metadata.rs (97%) rename block/src/formats/vhdx/{internal/mod.rs => parser.rs} (97%) delete mode 100644 block/src/formats/vhdx/worker/mod.rs diff --git a/block/src/formats/vhdx/internal/bat.rs b/block/src/formats/vhdx/bat.rs similarity index 82% rename from block/src/formats/vhdx/internal/bat.rs rename to block/src/formats/vhdx/bat.rs index 97dc4745c..56c11e83d 100644 --- a/block/src/formats/vhdx/internal/bat.rs +++ b/block/src/formats/vhdx/bat.rs @@ -14,17 +14,17 @@ use super::metadata::DiskSpec; use crate::aligned_file::AlignedFile; // Payload BAT Entry States -pub const PAYLOAD_BLOCK_NOT_PRESENT: u64 = 0; -pub const PAYLOAD_BLOCK_UNDEFINED: u64 = 1; -pub const PAYLOAD_BLOCK_ZERO: u64 = 2; -pub const PAYLOAD_BLOCK_UNMAPPED: u64 = 3; -pub const PAYLOAD_BLOCK_FULLY_PRESENT: u64 = 6; -pub const PAYLOAD_BLOCK_PARTIALLY_PRESENT: u64 = 7; +pub(super) const PAYLOAD_BLOCK_NOT_PRESENT: u64 = 0; +pub(super) const PAYLOAD_BLOCK_UNDEFINED: u64 = 1; +pub(super) const PAYLOAD_BLOCK_ZERO: u64 = 2; +pub(super) const PAYLOAD_BLOCK_UNMAPPED: u64 = 3; +pub(super) const PAYLOAD_BLOCK_FULLY_PRESENT: u64 = 6; +pub(super) const PAYLOAD_BLOCK_PARTIALLY_PRESENT: u64 = 7; // Mask for the BAT state -pub const BAT_STATE_BIT_MASK: u64 = 0x07; +pub(super) const BAT_STATE_BIT_MASK: u64 = 0x07; // Mask for the offset within the file in units of 1 MB -pub const BAT_FILE_OFF_MASK: u64 = 0xFFFFFFFFFFF00000; +pub(super) const BAT_FILE_OFF_MASK: u64 = 0xFFFFFFFFFFF00000; #[sorted] #[derive(Error, Debug)] @@ -39,14 +39,14 @@ pub enum VhdxBatError { WriteBat(#[source] io::Error), } -pub type Result = result::Result; +pub(super) type Result = result::Result; #[derive(Default, Clone, Debug)] -pub struct BatEntry(pub u64); +pub(super) struct BatEntry(pub u64); impl BatEntry { // Read all BAT entries presented on the disk and insert them to a vector - pub fn collect_bat_entries( + pub(super) fn collect_bat_entries( f: &AlignedFile, disk_spec: &DiskSpec, bat_entry: &RegionTableEntry, @@ -79,7 +79,7 @@ impl BatEntry { } // Routine for writing BAT entries to the disk - pub fn write_bat_entries( + pub(super) fn write_bat_entries( f: &AlignedFile, bat_offset: u64, bat_entries: &[BatEntry], diff --git a/block/src/formats/vhdx/worker/sync.rs b/block/src/formats/vhdx/engine_sync.rs similarity index 97% rename from block/src/formats/vhdx/worker/sync.rs rename to block/src/formats/vhdx/engine_sync.rs index f75526972..292a4d442 100644 --- a/block/src/formats/vhdx/worker/sync.rs +++ b/block/src/formats/vhdx/engine_sync.rs @@ -11,9 +11,9 @@ use std::sync::{Arc, Mutex}; use vmm_sys_util::eventfd::EventFd; use crate::async_io::{AsyncIo, AsyncIoCompletion, AsyncIoError, AsyncIoOperation, AsyncIoResult}; -use crate::formats::vhdx::internal::Vhdx; +use crate::formats::vhdx::Vhdx; -pub struct VhdxSync { +pub(super) struct VhdxSync { vhdx_file: Arc>, eventfd: EventFd, completion_list: VecDeque, @@ -21,7 +21,7 @@ pub struct VhdxSync { } impl VhdxSync { - pub fn new(vhdx_file: Arc>, size: u64) -> Self { + pub(super) fn new(vhdx_file: Arc>, size: u64) -> Self { VhdxSync { vhdx_file, eventfd: EventFd::new(libc::EFD_NONBLOCK) @@ -120,7 +120,7 @@ mod tests { use super::*; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoOperation, OwnedIoBuffer}; - use crate::formats::vhdx::internal::Vhdx; + use crate::formats::vhdx::Vhdx; use crate::formats::vhdx::test_util::create_dynamic_vhdx; fn make_vhdx_sync(tf: &TempFile) -> (VhdxSync, u64) { diff --git a/block/src/formats/vhdx/internal/header.rs b/block/src/formats/vhdx/header.rs similarity index 96% rename from block/src/formats/vhdx/internal/header.rs rename to block/src/formats/vhdx/header.rs index d6aa7e93b..eedfe84eb 100644 --- a/block/src/formats/vhdx/internal/header.rs +++ b/block/src/formats/vhdx/header.rs @@ -21,7 +21,7 @@ const REGION_SIGN: u32 = 0x6967_6572; // "regi" const FILE_START: u64 = 0; // The first element const HEADER_1_START: u64 = 64 * 1024; // Header 1 start in Bytes const HEADER_2_START: u64 = 128 * 1024; // Header 2 start in Bytes -pub const REGION_TABLE_1_START: u64 = 192 * 1024; // Region 1 start in Bytes +pub(super) const REGION_TABLE_1_START: u64 = 192 * 1024; // Region 1 start in Bytes const REGION_TABLE_2_START: u64 = 256 * 1024; // Region 2 start in Bytes const HEADER_SIZE: u64 = 4 * 1024; // Each header is 64 KiB, but only first 4 kiB contains info @@ -84,16 +84,16 @@ pub enum VhdxHeaderError { WriteHeader(#[source] io::Error), } -pub type Result = result::Result; +pub(super) type Result = result::Result; #[derive(Clone, Debug)] -pub struct FileTypeIdentifier { +pub(super) struct FileTypeIdentifier { pub _signature: u64, } impl FileTypeIdentifier { /// Reads the File Type Identifier structure from a reference VHDx file - pub fn new(f: &AlignedFile) -> Result { + pub(super) fn new(f: &AlignedFile) -> Result { let mut buf = [0u8; size_of::()]; f.read_exact_at(&mut buf, FILE_START) .map_err(VhdxHeaderError::ReadFileTypeIdentifier)?; @@ -108,7 +108,7 @@ impl FileTypeIdentifier { #[repr(C, packed)] #[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes)] -pub struct Header { +pub(super) struct Header { pub signature: u32, pub checksum: u32, pub sequence_number: u64, @@ -123,7 +123,7 @@ pub struct Header { impl Header { /// Reads the Header structure from a reference VHDx file - pub fn new(f: &AlignedFile, start: u64) -> Result
{ + pub(super) fn new(f: &AlignedFile, start: u64) -> Result
{ // Read the whole header into a buffer. We will need it for // calculating checksum. let mut buffer = [0; HEADER_SIZE as usize]; @@ -199,7 +199,7 @@ struct RegionTableHeader { impl RegionTableHeader { /// Reads the Region Table Header structure from a reference VHDx file - pub fn new(f: &AlignedFile, start: u64) -> Result { + pub(crate) fn new(f: &AlignedFile, start: u64) -> Result { // Read the whole header into a buffer. We will need it for calculating // checksum. let mut buffer = [0u8; REGION_SIZE as usize]; @@ -234,7 +234,7 @@ fn ranges_overlap(a_start: u64, a_end: u64, b_start: u64, b_end: u64) -> bool { a_start < b_end && b_start < a_end } -pub struct RegionInfo { +pub(super) struct RegionInfo { pub bat_entry: RegionTableEntry, pub mdr_entry: RegionTableEntry, pub region_entries: BTreeMap, @@ -243,7 +243,7 @@ pub struct RegionInfo { impl RegionInfo { /// Collect all entries in a BTreeMap from the Region Table and identifies /// BAT and metadata regions - pub fn new(f: &AlignedFile, region_start: u64, entry_count: u32) -> Result { + pub(super) fn new(f: &AlignedFile, region_start: u64, entry_count: u32) -> Result { let mut bat_entry: Option = None; let mut mdr_entry: Option = None; @@ -321,7 +321,7 @@ impl RegionInfo { #[repr(C, packed)] #[derive(Clone, Copy, Debug, FromBytes)] -pub struct RegionTableEntry { +pub(super) struct RegionTableEntry { guid: [u8; 16], pub file_offset: u64, pub length: u32, @@ -335,7 +335,7 @@ enum HeaderNo { /// Contains the information from the header of a VHDx file #[derive(Clone, Debug)] -pub struct VhdxHeader { +pub(super) struct VhdxHeader { _file_type_identifier: FileTypeIdentifier, header_1: Header, header_2: Header, @@ -345,7 +345,7 @@ pub struct VhdxHeader { impl VhdxHeader { /// Creates a VhdxHeader from a reference to a file - pub fn new(f: &AlignedFile) -> Result { + pub(super) fn new(f: &AlignedFile) -> Result { Ok(VhdxHeader { _file_type_identifier: FileTypeIdentifier::new(f)?, header_1: Header::new(f, HEADER_1_START)?, @@ -415,14 +415,14 @@ impl VhdxHeader { VhdxHeader::update_header(f, Ok(header_1), Ok(header_2), guid) } - pub fn update(&mut self, f: &AlignedFile) -> Result<()> { + pub(super) fn update(&mut self, f: &AlignedFile) -> Result<()> { let headers = VhdxHeader::update_headers(f, Ok(self.header_1), Ok(self.header_2), 0)?; self.header_1 = headers.0; self.header_2 = headers.1; Ok(()) } - pub fn region_entry_count(&self) -> u32 { + pub(super) fn region_entry_count(&self) -> u32 { self.region_table_1.entry_count } } diff --git a/block/src/formats/vhdx/internal/io.rs b/block/src/formats/vhdx/io.rs similarity index 98% rename from block/src/formats/vhdx/internal/io.rs rename to block/src/formats/vhdx/io.rs index 4909e607f..e6c96ee56 100644 --- a/block/src/formats/vhdx/internal/io.rs +++ b/block/src/formats/vhdx/io.rs @@ -33,7 +33,7 @@ pub enum VhdxIoError { WriteBat(#[source] VhdxBatError), } -pub type Result = result::Result; +pub(super) type Result = result::Result; macro_rules! align { ($n:expr, $align:expr) => {{ $n.div_ceil($align) * $align }}; @@ -51,7 +51,7 @@ struct Sector { impl Sector { /// Translate sector index and count of data in file to actual offsets and /// BAT index. - pub fn new( + pub(crate) fn new( disk_spec: &DiskSpec, bat: &[BatEntry], sector_index: u64, @@ -86,7 +86,7 @@ impl Sector { /// VHDx IO read routine: requires relative sector index and count for the /// requested data. -pub fn read( +pub(super) fn read( f: &AlignedFile, buf: &mut [u8], disk_spec: &DiskSpec, @@ -138,7 +138,7 @@ pub fn read( /// VHDx IO write routine: requires relative sector index and count for the /// requested data. -pub fn write( +pub(super) fn write( f: &AlignedFile, buf: &[u8], disk_spec: &mut DiskSpec, diff --git a/block/src/formats/vhdx/internal/metadata.rs b/block/src/formats/vhdx/metadata.rs similarity index 97% rename from block/src/formats/vhdx/internal/metadata.rs rename to block/src/formats/vhdx/metadata.rs index e6ae344c9..1bf571050 100644 --- a/block/src/formats/vhdx/internal/metadata.rs +++ b/block/src/formats/vhdx/metadata.rs @@ -21,7 +21,7 @@ const METADATA_TABLE_MAX_SIZE: usize = METADATA_ENTRY_SIZE * (METADATA_MAX_ENTRI const METADATA_FLAGS_IS_REQUIRED: u32 = 0x04; -pub const BLOCK_SIZE_MIN: u32 = 1 << 20; // 1 MiB +pub(super) const BLOCK_SIZE_MIN: u32 = 1 << 20; // 1 MiB const BLOCK_SIZE_MAX: u32 = 256 << 20; // 256 MiB const MAX_SECTORS_PER_BLOCK: u64 = 1 << 23; @@ -93,10 +93,10 @@ pub enum VhdxMetadataError { UnsupportedFlag, } -pub type Result = result::Result; +pub(super) type Result = result::Result; #[derive(Default, Clone, Debug)] -pub struct DiskSpec { +pub(super) struct DiskSpec { pub disk_id: u128, pub image_size: u64, pub block_size: u32, @@ -112,7 +112,7 @@ pub struct DiskSpec { impl DiskSpec { /// Parse all metadata from the provided file and store info in DiskSpec /// structure. - pub fn new(f: &AlignedFile, metadata_region: &RegionTableEntry) -> Result { + pub(super) fn new(f: &AlignedFile, metadata_region: &RegionTableEntry) -> Result { let mut disk_spec = DiskSpec::default(); let mut metadata_presence: u16 = 0; let mut offset = 0; @@ -270,7 +270,7 @@ struct MetadataTableHeader { } impl MetadataTableHeader { - pub fn new(buffer: &[u8]) -> Result { + pub(crate) fn new(buffer: &[u8]) -> Result { let metadata_table_header = MetadataTableHeader::read_from_bytes(buffer).unwrap(); if metadata_table_header.signature != METADATA_SIGN { @@ -291,7 +291,7 @@ impl MetadataTableHeader { #[repr(C, packed)] #[derive(Default, Debug, Clone, Copy, FromBytes)] -pub struct MetadataTableEntry { +pub(super) struct MetadataTableEntry { item_id: [u8; 16], offset: u32, length: u32, diff --git a/block/src/formats/vhdx/mod.rs b/block/src/formats/vhdx/mod.rs index f9d7d580c..ea15156bf 100644 --- a/block/src/formats/vhdx/mod.rs +++ b/block/src/formats/vhdx/mod.rs @@ -9,19 +9,23 @@ //! Provides [`VhdxDisk`], the `DiskFile` wrapper for dynamic VHDX //! images. -pub mod internal; +mod bat; +mod engine_sync; +mod header; +mod io; +mod metadata; +mod parser; #[cfg(test)] -pub(crate) mod test_util; -pub(crate) mod worker; +mod test_util; use std::fs::File; -use std::io; +use std::io::Error as IoError; use std::os::fd::AsRawFd; use std::sync::{Arc, Mutex}; -pub use internal::{Vhdx, VhdxError}; +pub use parser::{Vhdx, VhdxError}; -use self::worker::sync::VhdxSync; +use self::engine_sync::VhdxSync; use crate::async_io::{AsyncIo, BorrowedDiskFd, DiskFileError}; use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; use crate::{Error, disk_file}; @@ -92,7 +96,7 @@ impl disk_file::Resizable for VhdxDisk { fn resize(&mut self, _size: u64) -> BlockResult<()> { Err(BlockError::new( BlockErrorKind::UnsupportedFeature, - DiskFileError::ResizeError(io::Error::other("resize not supported for VHDX")), + DiskFileError::ResizeError(IoError::other("resize not supported for VHDX")), ) .with_op(ErrorOp::Resize)) } diff --git a/block/src/formats/vhdx/internal/mod.rs b/block/src/formats/vhdx/parser.rs similarity index 97% rename from block/src/formats/vhdx/internal/mod.rs rename to block/src/formats/vhdx/parser.rs index c8f5a2fd1..a739b1a6a 100644 --- a/block/src/formats/vhdx/internal/mod.rs +++ b/block/src/formats/vhdx/parser.rs @@ -13,17 +13,12 @@ use std::result; use remain::sorted; use thiserror::Error; -use self::bat::{BatEntry, VhdxBatError}; -use self::header::{RegionInfo, RegionTableEntry, VhdxHeader, VhdxHeaderError}; -use self::io::VhdxIoError; -use self::metadata::{DiskSpec, VhdxMetadataError}; +use super::bat::{BatEntry, VhdxBatError}; +use super::header::{self, RegionInfo, RegionTableEntry, VhdxHeader, VhdxHeaderError}; +use super::io::{self, VhdxIoError}; +use super::metadata::{DiskSpec, VhdxMetadataError}; use crate::aligned_file::AlignedFile; -mod bat; -mod header; -mod io; -mod metadata; - #[sorted] #[derive(Error, Debug)] pub enum VhdxError { @@ -43,7 +38,7 @@ pub enum VhdxError { WriteFailed(#[source] VhdxIoError), } -pub type Result = result::Result; +pub(super) type Result = result::Result; #[derive(Debug)] pub struct Vhdx { diff --git a/block/src/formats/vhdx/worker/mod.rs b/block/src/formats/vhdx/worker/mod.rs deleted file mode 100644 index 461f37061..000000000 --- a/block/src/formats/vhdx/worker/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved. -// -// SPDX-License-Identifier: Apache-2.0 - -//! Sync I/O worker for VHDX images. - -pub(crate) mod sync;