Use two passes to first reserve PCI device IDs and then allocate them
when adding the devices to the bus. This prevents a situation where an
anonymous PCI device allocation clashes with an explicitly allocated PCI
device ID.
Signed-off-by: Rob Bradford <rbradford@meta.com>
We pass the device ID from the config to the allocation routine, where
it is then used as the preferred device ID alongside the existing PCI
segment ID.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Signed-off-by: Rob Bradford <rbradford@meta.com>
Validate the PCI device ID are within range and not using the reserved
value. We need this option to ensure that invalid device IDs received
via an API call result in an error as soon as possible. In this case,
this would be after deserialization. On this code path, validation via
`parse` is skipped and must be invoked by calling `validate`.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Signed-off-by: Rob Bradford <rbradford@meta.com>
For those devices types that have the the ability to support specifying
the PCI device ID add it to their help syntax.
Signed-off-by: Rob Bradford <rbradford@meta.com>
This can be used in a two pass approach where all configs that can hold
PCI devices are evaluated to reserve any specific PCI device IDs they
may need. Those device IDs will later be allocated when the devices are
added to the bus. The tri-state Free, Reserved, Allocated also catches
the problem of hotplugging a device with a specific, already used,
device ID.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Next to tests for `allocate_device_id`, we introduce a new constructor
`new_without_address_manager`, only available in the test build. As
there is no way to instantiate an `AddressManager` in the tests, we use
this constructor to work around this.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit refactors the PCI bus struct. It has two major focuses.
First, we change the type of `device_ids` in `PciBus` to an array. A
fixed-size array better reflects real PCI bus constraints, especially
its limited number of PCI devices. Moreover, it can't be grown
accidentally.
The second focus is changing the type of the key of `devices` in
`PciBus` to `u8`, since device IDs are not allowed to exceed 31. We
furthermore replace magic numbers with constants and make them publicly
available so we can use them in a follow-up change when parsing user
input.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
Use `wait_until()` with the SSH command for detecting if the net device
is present/absent as part of hotplugging/unplugging.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Use `wait_until()` with the SSH command for detecting if the block
device is present/absent as part of hotplugging/unplugging.
Signed-off-by: Rob Bradford <rbradford@meta.com>
The vhost-user tests uses SSH and checking the RAM to test for the
liveness of the VM - replace the explicit sleep before them with
`wait_until()` allowing them to potentially finish earlier.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Rather than use a fixed time to wait for the socket to be opened instead
test for its existence using `wait_until()`.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Use new `wait_until()` and existing boot response mechanisms to remove
explicit sleeps from these tests.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Calling vm.add-user-device a second time with a socket path already
in use makes the VMM thread block indefinitely inside
vfio_user::Client::new(). libvfio-user servers (SPDK, the reference
libvfio-user daemon) accept a single active client per socket, so
the second connect(2) succeeds at the OS level but the handshake
recvmsg(2) waits for a response that never arrives.
All subsequent API requests queue behind the stuck VMM event loop
and also hang (vm.info, vmm.ping, vm.remove-device). The VM itself
keeps running on vcpu threads, making the symptom confusing: the
guest looks healthy, only the API is unreachable.
This is easy to hit from management software that uses an idempotent
reconcile / ensure pattern for user devices.
Reject the call up-front when another user_device already has the
same socket path, returning an HTTP 500 with a descriptive
UserDeviceSocketInUse error in milliseconds instead of hanging.
Signed-off-by: Max Makarov <maxpain@linux.com>
Several error mappings in vm.rs dropped the underlying error with
map_err(|_| ...), making failures harder to diagnose. Preserve the
source error by adding #[source] fields to InitramfsLoad and ErrorNmi.
- InitramfsLoad: now wraps std::io::Error from seek/rewind operations
- ErrorNmi: now wraps cpu::Error from the CPU manager nmi() call
Partially addresses #7563
Signed-off-by: Keith Adler <kadler@cloudflare.com>
Add micro_bench_qcow_batch_write which builds a batch of num_ops
write requests and submits them all at once through
submit_batch_requests. Writes in QcowAsync are synchronous (COW
path), so this measures whether batching reduces per-request
overhead compared to individual write_vectored calls.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_l2_cache_miss which reads one cluster
from each of num_ops distinct L2 tables through the QcowAsync
io_uring path, forcing L2 cache eviction on nearly every read.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add sparse_qcow_async_tempfile which creates a sparse QCOW2 image
with one cluster per L2 table and opens it via QcowDiskAsync.
Mirrors the existing sparse_qcow_tempfile for io_uring benchmarks.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_write which writes clusters into an
empty QCOW2 image through the QcowAsync io_uring path. Writes
in QcowAsync are synchronous due to COW metadata allocation, so
this measures the write path overhead through the async code path.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add empty_qcow_async_tempfile which creates an empty QCOW2 image
and opens it via QcowDiskAsync. Mirrors the existing
empty_qcow_tempfile for io_uring write benchmarks.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_compressed_read which reads from a
zlib compressed QCOW2 image through the QcowAsync io_uring path.
Compressed clusters take the sync fallback since they require
decompression.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add compressed_qcow_async_tempfile which creates a zlib compressed
QCOW2 image via qemu-img and opens it via QcowDiskAsync. Mirrors
the existing compressed_qcow_tempfile for io_uring benchmarks.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_backing_read which reads clusters from
a QCOW2 overlay through the QcowAsync io_uring path. All reads
fall through to the backing file, exercising the sync fallback
path in QcowAsync.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add qcow_async_overlay_tempfile which creates a QCOW2 overlay
backed by a RAW file and opens it via QcowDiskAsync. Mirrors
the existing qcow_overlay_tempfile for io_uring benchmarks.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_multi_cluster_read which reads 8
contiguous clusters (512 KiB) per request through the QcowAsync
io_uring path. With coalesced mappings this can hit the io_uring
fast path for a single Readv SQE.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_random_read which reads clusters in
random order through the QcowAsync io_uring path. This mirrors
the existing sync random read benchmark and measures io_uring
completion handling under random access patterns.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_batch_read which builds a batch of num_ops
read requests and submits them all at once through
submit_batch_requests. This exercises the io_uring batch
submission path added in qcow_async, where multiple SQEs are
packed into a single io_uring_enter call.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_async_read which reads clusters through the
QcowDiskAsync io_uring backend. Single allocated cluster reads go
through io_uring for true asynchronous completion, unlike the sync
benchmarks which use QcowDiskSync with blocking I/O.
Workloads: 128 and 256 clusters.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_l2_cache_miss which reads one cluster from each
of num_ops distinct L2 tables in a sparsely allocated image. Clusters
are spaced L2_ENTRIES_PER_TABLE apart so every read touches a different
L2 table, forcing eviction when num_ops exceeds the cache capacity.
Workloads: 128 and 256 L2 tables.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add sparse_qcow_tempfile() which creates a QCOW2 image with one
allocated cluster per L2 table, spread across num_l2_tables distinct
L2 tables. Reading these clusters in sequence forces L2 cache misses
when the count exceeds the cache capacity.
Also add the L2_ENTRIES_PER_TABLE constant, 8192 for 64 KiB clusters.
To be used by the L2 cache cold miss benchmark.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_multi_cluster_read which issues large reads
spanning 8 contiguous clusters (512 KiB) per read_vectored call.
This exercises the mapping coalesce path where multiple L2 entries
are merged into fewer host I/O operations.
Workloads: 128 and 256 total clusters (16 and 32 reads).
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_compressed_read which reads clusters from a
zlib compressed QCOW2 image. Every cluster triggers decompression,
isolating the decompression overhead from the normal allocated cluster
read path.
Workloads: 128 and 256 clusters.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add compressed_qcow_tempfile() which creates a zlib compressed QCOW2
image by populating a RAW tempfile with data and converting it via
qemu-img convert -c. Every cluster in the resulting image is stored
compressed so reads exercise the decompression path.
To be used by the compressed read benchmark.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_cow_write which writes clusters into a QCOW2
overlay backed by a raw file. Each write triggers copy-on-write:
cluster allocation, L2 and refcount table updates, then the data
write. This measures COW allocation overhead compared to writing
into a plain empty image.
Workloads: 128 and 256 clusters.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_backing_read which reads clusters from a QCOW2
overlay where all data lives in a raw backing file. Every read falls
through the L2 lookup to the backing file, exercising the backing
chain read path.
Workloads: 128 and 256 clusters.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add qcow_overlay_tempfile() which creates a raw backing file with
pre-populated data and a QCOW2 overlay on top with no allocated
clusters. The overlay is opened with backing file support via
QcowDiskSync so reads fall through to the backing file.
To be used by backing file read and copy-on-write write
benchmarks.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_random_read which reads clusters from a
prepopulated qcow2 image in a deterministic pseudo-random order.
Unlike the sequential read benchmark, this exercises L2 cache miss
and eviction behaviour under random access patterns.
Uses Fisher-Yates shuffle with DefaultHasher for reproducible
permutation across runs.
Two TEST_LIST entries: micro_block_qcow_random_read_128_us and
micro_block_qcow_random_read_256_us with 128 and 256 cluster
workloads.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add deterministic_permutation() which produces a reproducible
pseudo random permutation of [0, n) using a Fisher-Yates shuffle
seeded by DefaultHasher. This is used by the random read micro
benchmarks to generate a fixed access pattern that is identical
across runs.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_fsync which writes num_ops clusters into an
empty qcow2 image to dirty L2 and refcount metadata then times a
single fsync call that flushes all dirty tables to disk. This
isolates the metadata flush cost which scales with the number of
dirty L2 table entries and refcount blocks.
Two TEST_LIST entries: micro_block_qcow_fsync_64_us and
micro_block_qcow_fsync_256_us with 64 and 256 cluster workloads.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add micro_bench_qcow_punch_hole which times punch_hole calls through
QcowSync on a prepopulated qcow2 image. Each call deallocates one
cluster exercising deallocate_bytes with refcount decrement and
fallocate punch_hole on the host file.
Two TEST_LIST entries: micro_block_qcow_punch_hole_64_us and
micro_block_qcow_punch_hole_256_us with 64 and 256 cluster workloads.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>