Commit Graph

10131 Commits

Author SHA1 Message Date
Anatol Belski
835caf9413 block: Remove DiskBackend dispatch enum
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>
2026-04-22 18:04:16 +00:00
Anatol Belski
6b6150ebfc vmm: device_manager: Use block factory for disk opening
Replace the manual match block that constructed each disk format
backend with a single call to block::factory::open_disk. The factory
handles file opening, format detection, async/sync backend selection
and logging internally.

Remove imports and errors for individual format types and helper
functions that are no longer called directly. The factory returns
BlockError with path and operation context attached, surfaced via
the existing Disk variant.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-22 18:04:16 +00:00
Anatol Belski
03a5c29c48 block: factory: Add test for sync fallback
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>
2026-04-22 18:04:16 +00:00
Anatol Belski
37693aa141 block: factory: Add test for readonly open
Verify that open_disk() succeeds with readonly=true on a RAW image.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-22 18:04:16 +00:00
Anatol Belski
78784c2a3f block: factory: Add test for QCOW2 image detection
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>
2026-04-22 18:04:16 +00:00
Anatol Belski
01c4e0512f block: factory: Add test for RAW image detection
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>
2026-04-22 18:04:16 +00:00
Anatol Belski
9ada7a9afd block: factory: Add test for nonexistent path
Verify that open_disk() returns BlockErrorKind::Io when the disk
image file does not exist.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-22 18:04:16 +00:00
Anatol Belski
cba2b7f773 block: factory: Add disk image factory module
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>
2026-04-22 18:04:16 +00:00
Wei Liu
d56253196b vmm: Enforce threads_per_core to be at most two
Microsoft Hypervisor's hyperclear technology supports at most two
threads per core.

Practically all x64 CPUs nowadays only support two threads per core.
Enforce this in the common code.

Assisted-by: OpenAI:ChatGPT-5.4
[Test cases written by an LLM ]
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2026-04-22 01:01:06 +00:00
Demi Marie Obenour
7c44f49293 block: Move request code to its own module
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>
2026-04-21 23:35:26 +00:00
Wei Liu
8f972567d0 docs: Standardize the format for disclosing LLM-assisted changes
This is adopted from the Linux kernel development process.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2026-04-21 21:48:59 +00:00
Anatol Belski
21cd13df01 block: Rename AsyncDiskFile::new_async_io to create_async_io
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>
2026-04-21 10:36:52 +00:00
Saravanan D
5a14d0e2e0 vmm: clear VFIO MMIO regions in DeviceManager::drop
DeviceManager and VfioPciDevice both hold Arc<MmapRegion> for
each VFIO BAR mmap window. During VM shutdown, VfioPciDevice
drops after DeviceManager::Drop::drop (via device_tree
field drop). Without clearing DeviceManager's clones first,
VfioPciDevice::unmap_mmio_regions decrements the Arc but
does not reach zero, munmap never fires, the VFIO device
file VMAs survive, and VFIO_GROUP_UNSET_CONTAINER returns
EBUSY.

Clear DeviceManager's mmio_regions in Drop::drop so
VfioPciDevice is the sole Arc owner at drop time and ensure
VFIO_GROUP_UNSET_CONTAINER ioctl success.

Remove redundant .clone() on the mmio_regions() return value
in the eject_device() hot-unplug path.

Add detail comments

Signed-off-by: Saravanan D <saravanand@crusoe.ai>
2026-04-20 18:10:17 +00:00
Anatol Belski
7294ca99cf block: raw: Return BlockResult from RawFileAsync::new
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>
2026-04-20 18:09:27 +00:00
Anatol Belski
cd9fc52472 block: vhdx: Classify VhdxError variants in VhdxDiskSync::new
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>
2026-04-20 18:09:27 +00:00
Anatol Belski
4416a582c8 block: vhdx: Remove catch all in physical_size boundary
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>
2026-04-20 18:09:27 +00:00
Anatol Belski
da64acb775 block: vhd: Propagate logical_size error at boundary
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>
2026-04-20 18:09:27 +00:00
Anatol Belski
a8d339c9e7 block: vhd: Remove catch all in physical_size boundary
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>
2026-04-20 18:09:27 +00:00
Anatol Belski
519acda794 block: qcow: Test compressed cluster read via QcowFile
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
365ed236cc block: qcow: Test compressed cluster read via QcowDiskAsync
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
16abb28b85 block: qcow: Test compressed cluster read via QcowDiskSync
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
79c6ce43ef block: qcow: Test decompress_cluster with corrupt input
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
ed9154b39d block: qcow: Test decompress_cluster deflate roundtrip
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
a502354619 block: qcow: Test pread_alloc with offset reads and EOF
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
158882e6dd block: qcow: Add compress_allocated_clusters test helper
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
5504ad753a block: qcow: Move compressed read decompression out of lock
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
659f7c17e5 block: qcow: Cache cluster_size in per queue structs
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>
2026-04-20 18:09:12 +00:00
Anatol Belski
d9b188c1be block: qcow: Add pread_alloc and decompress_cluster helpers
Add two reusable helpers for the compressed cluster read path:

- pread_alloc(fd, offset, len) allocates a buffer and fills it with
  pread_exact, returning the owned Vec.
- decompress_cluster(compressed, cluster_size, decoder) allocates the
  output buffer, decodes via the Decoder trait, and validates that the
  decoder produced exactly cluster_size bytes.

These will be used by QcowSync, QcowAsync, Qcow2Backing, and the
legacy QcowFile.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:12 +00:00
Anatol Belski
78a05ab0c1 test_infra: Test stale process group is replaced
Spawn a process that exits immediately, then spawn another under
the same test name. Verify the stale group is detected and a fresh
group is created for the second child.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
0a2d078479 test_infra: Test cleanup of unknown name returns false
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
6e8c2bd2b3 test_infra: Test multiple spawns share one process group
Spawn two processes under the same test name and verify they
have the same group PID. Cleanup kills both.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
6453a9a91a test_infra: Test ProcessRegistry spawn and cleanup
Spawn a sleep process through the registry, verify it is alive,
call cleanup and verify the process was killed.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
a597c74385 performance-metrics: Replace pkill cleanup with ProcessRegistry
Use thread::Builder to give the test thread a name matching the
test so Guest picks it up automatically.  After every test, call
ProcessRegistry::cleanup() to kill the process group instead of
the old pkill based cleanup_stale_processes().

Remove cleanup_stale_processes() and its call sites.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
18513ead0c test_infra: Wire spawn sites through ProcessRegistry
Route GuestCommand::spawn(), iperf3, and ethr spawns through
ProcessRegistry::spawn() when the guest has a test_name.  This
places every child process into the test's shared process group
so they can all be killed with a single killpg call.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Anatol Belski
3ab2c60489 test_infra: Add ProcessRegistry for per test process groups
Add a global registry that maps test names to process group IDs.
The first child spawned for a test creates a new process group
via setpgid(0, 0); subsequent children join it via setpgid(0, pgid).
A single killpg(pgid, SIGKILL) tears down all processes the test
spawned.

Also add Guest.test_name, populated automatically from the current
thread name at construction time.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-04-20 18:09:02 +00:00
Rob Bradford
9a14fdb7f8 virtio-devices: block: Correctly report number of bytes written
The driver needs to be notified with the number of bytes written by the
device. Ensure that the correct number of bytes is reported.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
334b900fcd vhost_user_block: Correctly report number of used bytes
The number of bytes written into descriptors should be reported for
`add_used()`. Here it is either just the status byte or also the size of
serial ID for the block device.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
7b07c3a194 virtio-devices: rng: Fill the entire descriptor chain
The virtio spec allows a chain of writable descriptors however the rng
device was assuming just a single writable descriptor. Instead fill in
all writable descriptors. There is no status byte (unlike e.g. block)
and instead 0 bytes used is used to indicate error.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
ae3282dc86 virtio-devices: pmem: Write a status respone for invalid commands
The virtio spec requires that a status response is always written on
error. This was missing from the path where we had a valid request but
not for one we support.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
8685eb5c53 virtio-devices: pmem: Relax descriptor size check
The virtio spec allows the use of larger descriptors (for future
expansion). Relax the bounds check to only reject descriptors that are
too small.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
82d426162d virtio-devices: mem: Relax descriptor size check
The virtio spec allows the use of larger descriptors (for future
expansion). Relax the bounds check to only reject descriptors that are
too small.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Rob Bradford
2a089db269 virtio-devices: net: Report correct used length on TX and ctrl
The virtio spec says the used-ring length is bytes the device wrote to
device writable descriptors. The net TX descriptors are device readable
only (the device wrote nothing back) so the length needs to be 0. On the
ctrl queue the number of bytes reported was wrongly the size of the
status descriptor not the number of bytes written (the descriptor is
permitted to be larger).

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 18:08:34 +00:00
Muminul Islam
305451cce4 scripts: dev_cli: Add signal handling for graceful cleanup
During development, it is common to cancel a running test and
rerun it after making changes. However, pressing Ctrl+C while
dev_cli.sh runs long-running container commands (wget, qemu-img,
cargo build, etc.) does not reliably terminate the process.
Bash defers signal handling while a foreground process is
running, so the trap only fires after the docker run command
returns. This makes it difficult to cancel and restart quickly.

Fix this by introducing a run_container() wrapper that runs
docker in the background and uses 'wait', which is immediately
interruptible by signals. A cleanup() trap handler is set for
SIGINT and SIGTERM that kills the named container, the tracked
background PID, and any remaining child processes.

Each docker run invocation is assigned a unique --name based
on the script PID (clh-dev-$$) to allow targeted cleanup.
The interactive shell (cmd_shell) is left unwrapped since it
needs foreground terminal I/O.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2026-04-20 13:49:58 +00:00
Rob Bradford
ae646f9220 tests: Use wait_until() in test_pci_device_id
The SSH connection may fail initially when under load so use
`wait_until()` to allow retries.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 12:35:12 +00:00
Rob Bradford
a77b6231b4 tests: Ensure that virtiofsd has exited before hotplugging
Fix test flakiness where the virtiofsd daemon was still running and
hotplugging was trying to reach the old version. Cleanup the socket so
that waiting for it actually waits for the new instance.

Signed-off-by: Rob Bradford <rbradford@meta.com>
2026-04-20 12:35:12 +00:00
Keith Adler
926dd1e141 vmm, devices: Add fw_cfg string item support
QEMU supports passing inline string values to the guest via fw_cfg
(-fw_cfg name=...,string=...). Cloud Hypervisor previously only
supported file-backed fw_cfg items. This adds the 'string' option
so users can pass values like OVMF's X-PciMmio64Mb without creating
a temporary file on the host.

Each fw_cfg item now accepts exactly one of 'file' or 'string'.
The FwCfgInvalidItem invariant is validated in PayloadConfig::validate()
(via FwCfgConfig::validate()), covering both CLI and JSON API paths.
The populate_fw_cfg match arm uses unreachable!() since validation
guarantees the invariant holds at that point.

CLI syntax:
  --fw-cfg-config items=[name=opt/ovmf/X-PciMmio64Mb,string=262144]

Signed-off-by: Keith Adler <kadler@cloudflare.com>
2026-04-20 09:39:56 +00:00
Keith Adler
e4e3375a8d vmm: move fw_cfg validation into PayloadConfig::validate()
Move FwCfgMissingKernel/Cmdline/Initramfs error variants from
ValidationError into PayloadConfigError. Change FwCfgConfig::validate()
to take &PayloadConfig instead of &VmConfig and return
PayloadConfigError. Wire the call through PayloadConfig::validate()
so both CLI and JSON API paths are covered.

Signed-off-by: Keith Adler <kadler@cloudflare.com>
2026-04-20 09:39:56 +00:00
Anirudh Rayabharam
a10d9a3099 tests: Ignore live migration tests on mshv arm64
Live migration is not yet supported on mshv arm64. Annotate the
applicable integration tests with cfg_attr to ignore them for that
configuration.

Signed-off-by: Anirudh Rayabharam <anrayabh@microsoft.com>
2026-04-17 18:05:01 +00:00
Ruben Hakobyan
ea2df946f6 ci: Add CI jobs for KVM SEV-SNP
Add build and clippy jobs for kvm+sev_snp+igvm+fw_cfg feature combination.

Signed-off-by: Keith Adler <kadler@cloudflare.com>
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
2026-04-17 12:28:55 +00:00
Dylan Reid
d5179a73c2 vmm: use 64-bit BARs for hotplugged virtio block devices
Boot-time block devices on PCI segment 0 use 32-bit BARs so early
firmware can access them without additional identity mapping in the
firmware page tables. However, hot-plugged block devices are only ever
seen by the OS kernel which handles 64-bit BARs natively.

Switch hot-plugged block devices to 64-bit BARs to avoid exhausting the
scarce 32-bit MMIO window (typically 2-3 GB between RAM and 4 GB) when
many devices are hot-plugged.

Extract the BAR sizing decision into use_64bit_bar_for_virtio_device()
and thread an is_hotplug flag through add_virtio_pci_device(). Add unit
tests covering all relevant combinations.

Signed-off-by: Dylan Reid <dgreid@fb.com>
2026-04-17 12:28:55 +00:00