Verify that a freshly created sparse QCOW2 image reports a
physical size smaller than its logical size.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that try_clone preserves the backend dispatch for both
sync and io_uring backends.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that the sync backend disables batch requests and the
io_uring backend enables them.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
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 <anbelski@linux.microsoft.com>
Replace QcowDiskSync and QcowDiskAsync constructors in the
qcow_sync and qcow_async test modules with QcowDisk::new,
passing use_io_uring=false and use_io_uring=true respectively.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Update open_qcow2 to construct QcowDisk instead of choosing
between QcowDiskAsync and QcowDiskSync. The backend decision
is now made inside QcowDisk::create_async_io.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Introduce QcowDisk, a unified DiskFile implementation for QCOW2
disk images that handles backend selection at runtime via a
use_io_uring flag, matching the pattern used by FixedVhdDisk.
The wrapper delegates to QcowSync or QcowAsync based on the flag
and includes a compile time guard that returns an error when
io_uring is requested but the feature is not enabled.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The physical size of a fixed VHD is the data region plus the 512
byte footer. Verify it differs from the logical size.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Fixed VHDs do not support resize. Verify the error is returned.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that a cloned disk produces the same async I/O backend
as the original for both sync and io_uring paths.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that create_async_io dispatches to the correct backend
depending on use_io_uring. The sync backend does not support
batch requests, while the io_uring backend does.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that FixedVhdDisk::new with the sync backend reads the VHD
footer and reports the correct logical size.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Update open_fixed_vhd to construct FixedVhdDisk instead of choosing
between FixedVhdDiskAsync and FixedVhdDiskSync. The io_uring decision
is now made inside FixedVhdDisk::create_async_io().
Remove FixedVhdDiskSync and FixedVhdDiskAsync DiskFile wrapper structs
from fixed_vhd_sync.rs and fixed_vhd_async.rs. Only the FixedVhdSync
and FixedVhdAsync AsyncIo worker structs remain in those files.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Introduce FixedVhdDisk as a single DiskFile wrapper around FixedVhd.
It accepts a use_io_uring flag at construction time and dispatches to
FixedVhdSync or FixedVhdAsync inside create_async_io() accordingly.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that physical size of a sparse file is less than
logical size.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that try_clone preserves the backend variant for
each RawBackend: sync, AIO and io_uring.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify each RawBackend variant stores correctly and
create_async_io dispatches to the matching constructor.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that RawDisk with the sync backend reports the correct
logical size for a temporary file. Introduce make_raw_file helper
and TEST_SIZE constant for reuse in subsequent tests.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Update open_raw to construct RawDisk instead of choosing between
RawFileDisk, RawFileDiskSync and RawFileDiskAio. The backend decision
is now made inside RawDisk::create_async_io.
Remove the DiskFile wrapper structs from raw_sync.rs, raw_async.rs
and raw_async_aio.rs. Only the AsyncIo worker structs remain in those
files. Reduce their module visibility to pub(crate).
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add the DiskFile marker and AsyncDiskFile with try_clone and
create_async_io. The dispatch creates RawFileSync, RawFileAsync,
or RawFileAsyncAio depending on the backend selected at
construction. Alignment handling is left to the workers as is,
to be centralized separately per #8050.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Use the block device aware resize from RawFileDisk. For block
devices, verify the externally set size matches instead of
calling ftruncate. For regular files, truncate as usual.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Introduce the unified DiskFile wrapper for raw disk images. The
RawBackend enum selects between sync, io_uring, and AIO backends
at construction time.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The trait has no implementations. All format backends now implement
the composable disk_file traits instead. The DiskFileError and
AsyncIo types remain in async_io.rs as they are still used by
format workers.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
All disk format backends now implement AsyncFullDiskFile directly.
The DiskBackend enum that dispatched between Legacy and Next arms
is no longer needed since the factory returns trait objects and vmm
no longer constructs format types manually.
Replace DiskBackend with Box<dyn AsyncFullDiskFile> in the Block
struct and its constructor. Remove the DiskBackend::Next wrapping
in device_manager and the fuzz target.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that open_disk() falls back to synchronous backend when both
io_uring and AIO are disabled, and that the returned disk reports
the correct logical size.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Create a minimal QCOW2 temp file via QcowFile::new() and verify
that open_disk() detects it as ImageType::Qcow2.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that open_disk() detects a plain temporary file as RAW and
returns a working backend with synchronous fallback.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that open_disk() returns BlockErrorKind::Io when the disk
image file does not exist.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Introduce block::factory with open_disk() as the single entry point
for opening disk images. It handles file opening, format detection,
async I/O probing, and backend construction.
Per format helpers (open_fixed_vhd, open_raw, open_qcow2, open_vhdx)
prefer io_uring over AIO over synchronous fallback. Warnings only
fire when a backend was eligible but its runtime probe failed, not
when the user intentionally disabled it.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
There is no reason for most of the Request struct to be writable from
anywhere in the codebase. Encapsulate it.
Use getter functions for access outside the request module. Replace the
trivial setter for the writeback field with direct assignment.
No functional change intended.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
The new_ prefix in Rust conventionally denotes constructors that return
Self (e.g. Vec::new(), File::new()). AsyncDiskFile::new_async_io does
not return Self. It is a factory method that constructs and returns a
Box<dyn AsyncIo> worker bound to the disk file descriptor and
metadata. The create_ prefix communicates this: the caller receives
a freshly constructed object of a different type.
This rename touches every format backend in block plus two external
callers in virtio-devices and performance-metrics. Every change is a
mechanical s/new_async_io/create_async_io/ substitution. No functional
change.
Ref: #7877 (task 3.2.8)
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Change RawFileAsync::new() from std::io::Result to BlockResult,
aligning it with RawFileAsyncAio::new(). Each fallible call inside
the constructor now maps to BlockErrorKind::Io explicitly.
FixedVhdAsync::new() follows the same change since its only
fallible operation is constructing a RawFileAsync. The intermediate
DiskFileError::NewAsyncIo wrapping in both new_async_io() call
sites is no longer needed and is removed.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace the blanket BlockErrorKind::Io mapping with an explicit
match on all VhdxError variants:
NotVhdx, ParseVhdxHeader, ParseVhdxMetadata,
ParseVhdxRegionEntry => InvalidFormat
ReadBatEntry => CorruptImage
ReadFailed, WriteFailed => Io
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Vhdx::physical_size() can only return Error::GetFileMetadata.
Replace the catch-all arm with unreachable!() so future error
variants are not silently mapped to a generic Io classification.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace .unwrap() on FixedVhd::logical_size() with map_err in
DiskSize::logical_size() and new_async_io() for both FixedVhdDiskSync
and FixedVhdDiskAsync. The call is infallible today but unwrap hides
that assumption from callers and would panic if it ever changed.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
FixedVhd::physical_size() can only return Error::GetFileMetadata.
Replace the catch-all arm with unreachable!() so future error
variants are not silently mapped to a generic Io classification.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Write a known data pattern through QcowFile, compress all clusters
in place, reopen and read back via the seek based file_read path.
This covers the decompress_l2_cluster code path used by QcowFile
which is separate from the pread based path in QcowSync/QcowAsync.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Write a known data pattern, compress all clusters in place, reopen
through QcowDiskAsync, and read back from four concurrent queues
on separate threads. Each queue independently decompresses and
returns the correct data, validating the Arc<dyn Decoder> sharing.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Write a known data pattern to a QCOW2 image, convert all allocated
clusters to compressed format using compress_allocated_clusters,
reopen the image through QcowDiskSync, and verify that reading back
the full cluster returns the original data.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that decompress_cluster returns EIO when given invalid
compressed data that the decoder cannot process.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Compress a known 64K buffer with raw deflate, pass it through
decompress_cluster with ZlibDecoder, and verify the output matches
the original data.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that pread_alloc returns the correct data for a full read
from the start and a partial read at an arbitrary offset. Also
confirm that reading past the end of file produces an error.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add a test utility that converts standard uncompressed clusters in
a QCOW2 image into compressed clusters in place. It walks the L1/L2
tables, compresses each allocated cluster with raw deflate, appends
the compressed payload at the end of the file, and rewrites the L2
entry with the compressed layout.
This enables end to end testing of the compressed read path without
external tools like qemu-img.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Move decompression of compressed QCOW2 clusters out of the metadata
lock. Previously, reading a compressed cluster acquired a write lock
on metadata to perform in place decompression. Now, try_map_read
extracts the compressed layout (host offset, size) under a read lock
and returns it in the ClusterReadMapping::Compressed variant. Each
consumer (QcowSync, QcowAsync, Qcow2Backing, QcowFile) performs the
pread and decompression at the call site without holding any lock,
using the pread_alloc and decompress_cluster helpers.
Create the decoder once in QcowMetadata as Arc<dyn Decoder> and
share it via Arc::clone to QcowAsync, QcowSync, and Qcow2Backing
at construction time. This avoids per read RwLock acquisitions and
heap allocations. Add Send + Sync bounds to the Decoder trait.
This eliminates write lock contention on compressed reads, allowing
them to proceed concurrently with other read operations.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Cache the immutable cluster_size value at construction time in
QcowAsync, QcowSync, and Qcow2Backing. This avoids repeated RwLock
read acquisitions on the hot write and deallocation paths.
Replace QcowMetadata::cluster_offset() calls with inline bitmask
operations using the cached cluster_size. Remove the now unused
cluster_offset() method from QcowMetadata.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>