This removes a need to expose a method from the CpuManager back out to
the Vm which is called immediately after creating the CpuManager.
Signed-off-by: Rob Bradford <rbradford@meta.com>
create_cpu_nodes() emits one shared-L3 cache node per package when the
host reports a shared L3, but names every node with the constant
"l3-cache0". For a guest topology with packages >= 2 the generated
device tree carries the same name siblings.
Fixes: 5857d4851
Assisted-by: Claude:Opus-4.8 (1M context)
Signed-off-by: Isaku Yamahata <iyamahata@crusoe.ai>
The raw, qcow, and vhdx sync engines each carried an EventFd and a
VecDeque of completions and repeated the same push and signal idiom at
every completion site. Bundle the two into a SyncCompletionQueue with
complete, notifier, and next_completed, and route the three engines
through it. The repeated eventfd signal now lives in one place.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
test_create_fdt_with_devices() fails with a divide by zero. The caller
passes Some((0, 0, 0, 0)) for CPU topology as (threads_per_core,
cores_per_die, dies_per_package, packages). The valid default is
(1, 1, 1, 1), not all zero. Pass None because the eventual callee,
create_cpu_nodes(), checks None to get the right default value.
This affects the unit test only. A real VM never hits it because
VmConfig::validate() rejects zero with an error.
Fixes: 7fb980f17 ("arch, vmm: Pass cpu topology configuation to FDT")
Assisted-by: Claude:Opus-4.8 (1M context)
Signed-off-by: Isaku Yamahata <iyamahata@crusoe.ai>
Reject buf.len() that isn't sector_count * logical_sector_size in
io::read/write (VhdxIoError::InvalidBufferLength), and reject buf.len()
not a multiple of the sector size in Vhdx's Read/Write impl, before it's
converted to a sector count/index.
Signed-off-by: Alexander Lvov <alexander.lvov.git@gmail.com>
cloud-hypervisor always advertises a 512-byte logical block size over
virtio-blk, so a 4096-byte-sector VHDx image could never be addressed
correctly. Reject it at metadata parse time, matching QEMU's VHDx
support.
Signed-off-by: Alexander Lvov <alexander.lvov.git@gmail.com>
io::read/write sliced buf using free_sectors * SECTOR_SIZE, a hardcoded
512-byte constant, instead of the file's real logical sector size
([MS-VHDX] allows 512 or 4,096). On a 4096-byte-sector image, only the
first 512 bytes of each sector were transferred while the full 4096 was
reported as done.
Use sector.free_bytes instead.
Signed-off-by: Alexander Lvov <alexander.lvov.git@gmail.com>
Reimplement run_unaligned_operation over AlignedFile read_vectored_at
and write_vectored_at instead of scattering and gathering through the
per operation write_bytes_at and read_bytes_at closures. The aio and
uring engines already reach this helper for the O_DIRECT misaligned
case, so both now share the same vectored bounce path as the sync
engine and the scatter gather logic lives only in AlignedFile.
The operation iovecs point at the same memory that write_bytes_at and
read_bytes_at reach, and the aligned fast path already hands those
iovecs to the kernel, so the direct vectored call is equivalent. For
guest memory read targets the destination pages are marked dirty by
mark_read_dirty in execute_async before the operation is submitted,
independent of how the bounce copies bytes, so the raw iovec path
preserves dirty tracking. Drop the now unneeded mut bindings at the
call sites.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Cover the empty iovec noop, the fast path where iovecs go straight to
preadv or pwritev, and misaligned O_DIRECT scatter and gather across
multiple iovecs including a partial block read-modify-write.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add read_vectored_at and write_vectored_at to AlignedFile. They take
the aligned fast path with a single preadv or pwritev when the offset
and every iovec base and length satisfy the O_DIRECT alignment, and
otherwise bounce through an AlignedBuffer, scattering on read and
gathering with a read-modify-write on write.
Convert the raw sync engine to these methods and drop its raw preadv
and pwritev block. The methods are unsafe because their soundness
depends on the caller passing iovecs that describe valid memory for
iov_len bytes.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
CPU unplug requires co-operation between the guest and the VMM. Ensure
that the CPU the guest marks for eject is the one the VMM expects to be
removed. If the guest were to remove a different vCPU there would be
unexpected behaviour. Further ensure that the boot vCPU is never
unplugged.
Signed-off-by: Rob Bradford <rbradford@meta.com>
vm-memory 0.18 has renamed GuestMemory to GuestMemoryBackend, and made
GuestMemory refer to something less specific. For simplicity, we keep
using GuestMemoryBackend (formerly GuestMemory) everywhere for now. We
can adjust bounds to be less specific later if we find ourselves needing
the newly enabled flexibility.
Signed-off-by: Alyssa Ross <hi@alyssa.is>
Signed-off-by: Rob Bradford <rbradford@meta.com>
All error cases used `ValidationError` with a String containing context
about the error. This is suboptimal as the error kind itself does not
contain any context about the actual failure cause. Furthermore, this
does not allow to build error chains as underlaying errors are replaced
with the respective message string.
We improve the situation by introducing specific error variants for
failure case. This also allows us to test the respective code paths
more easily.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
This commit adds support for parsing `zone_updates` from the CLI
for the live migration and restore paths.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.
We consume `zone_updates` from `VmReceiveMigrationData` and
`RestoreConfig` to remap already existing `MemoryZone`s to different
host NUMA nodes. For now, we do not support further changes, such as
altering the size of the respective `MemoryZone`s.
These changes allow to migrate a VM to a host that has the capacity to
host the same `MemoryZone`s on a different NUMA layout.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
We use this function in the commit directly following this one to
update the VM configuration. This commit also introduces a test.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
It is possible to migrate a VM to a host that might have a different
but compatible NUMA configuration. For example, it should be possible
to move a `MemoryZone` from NUMA node 2 and 3 of the sender to nodes
0 and 1 on the receiver, given sender and receiver nodes are compatible
with respect to available memory.
In such a case, we need to adjust the mapping of guest memory to host
nodes. We need this information for live migration as well as for
snapshot (when performing cold migration). We consume this information
in the following commit.
Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de>
On-behalf-of: SAP pascal.scholz@sap.com
When a test process group cannot be reaped, the host is left with an
orphaned guest whose ports and interfaces block later tests. Continuing
produces cascading failures that hide the original issue.
Treat a failed cleanup as a test error. By default the runner aborts,
and under --continue-on-failure it records the failure and keeps going.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
ProcessRegistry::cleanup sent SIGKILL to a test's process group and
returned at once. SIGKILL is asynchronous, so a killed process could
still hold its boot listener socket when the next test started, causing
an EADDRINUSE bind failure.
Reap the group after the signal and wait for it to exit before
returning. Return an error if it does not exit within the timeout so a
caller can react to a guest that survived cleanup.
Since cleanup now reaps the whole group, the unit tests drop their Child
handles without waiting. They carry expect(clippy::zombie_processes),
since cleanup already reaps them.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The qcow2 backend caches L2 table and refcount updates in memory and
only writes them back on a guest-initiated flush, clean shutdown or
drop. A paused VM therefore leaves the on-disk image without the
mappings for any cluster allocated since the last guest flush: the
data clusters are present in the file, but nothing references them.
Anything that reads the image while the VM is paused sees those
writes as missing. Copying the disk alongside vm.snapshot (the
documented snapshot workflow) captures a stale image, and live
migration releases the disk locks after pausing so the destination
reopens the file with the same stale metadata. In both cases writes
the guest has completed, and may later read back, silently disappear.
Add a MetadataSync capability trait with a no-op default, fold it
into FullDiskFile, implement it for the qcow2 backend as a metadata
cache flush, and call it from the virtio-block pause path after
in-flight requests have drained. Pause is the quiesce point both
flows rely on, and it is a cold path, so the extra flush does not
affect runtime I/O.
Reproduced by writing to a qcow2 disk from the guest with O_DIRECT
and no explicit flush, pausing the VM and copying the image: qemu-img
map on the copy shows no mapped clusters and reads return zeros. With
this change the copy contains every completed write. A unit test
covers the same sequence at the format level: a completed write is
invisible to a fresh reader until sync_metadata, and visible after.
Signed-off-by: CMGS <ilskdw@gmail.com>
Each Windows integration test boots a full Windows Server guest using
several vCPUs and gigabytes of RAM. nextest runs up to one test per
logical CPU by default, so the whole suite started at once and thrashed
the host.
Add a dedicated 'windows' nextest profile that inherits from
integration and assigns the tests to a 'windows' test group capped at
four concurrent runs. Point the Windows test scripts at the profile and
drop the redundant retries flag, which now comes from the profile.
Running the tests in parallel is safe because every guest gets a unique
network via next_guest_id, so there is no shared address to conflict
over.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
When reconnecting to a vhost-user backend, Cloud Hypervisor keeps the
same queues and currently restarts them from avail_idx.
That can skip descriptors that were made available by the guest but not
completed before the old backend crashed. For queues where
VIRTIO_F_IN_ORDER was negotiated, used_idx is a safe completion
boundary, so reconnect can resume from used_idx and kick the queue if
work remains.
Do not do this when inflight tracking is active, because the backend
inflight state is the more precise recovery mechanism. Also leave queues
without VIRTIO_F_IN_ORDER on the existing avail_idx path, since used_idx
does not identify which descriptors completed for out-of-order devices.
Signed-off-by: Peter Delevoryas <pdel@meta.com>
Client connect retried for a full minute on every failure and did not
watch kill_evt for early exit, unlike reconnect, so teardown and
permanent connect errors both stalled for CONNECT_TIMEOUT.
Update the client path to watch kill_evt for early abort, fail
non-retryable errors immediately, and surface timeout with a dedicated
error.
Partially Fixes#8052
Signed-off-by: Chinmoy <daschinmoyy21@gmail.com>
Assisted-by: GLM 5.2
Exercise the EOPNOTSUPP fallback path using memfd, which shares
the same backing as tmpfs and triggers the fallback without
requiring privileges or a specific filesystem.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The WriteZeroesAt fallback means write_zeroes no longer fails on
filesystems that lack fallocate support. The skip is now dead
code.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Filesystems such as tmpfs do not support fallocate with
FALLOC_FL_ZERO_RANGE or FALLOC_FL_PUNCH_HOLE and return EOPNOTSUPP.
When a raw disk image lives on such a filesystem, virtio write zeroes
and discard requests fail with IOERR.
Use the WriteZeroesAt trait from vmm_sys_util through AlignedFile,
which already bundles fallocate with a positional write fallback.
For punch_hole, catch EOPNOTSUPP and fall back to the same trait.
The io_uring engine previously submitted fallocate directly through
the ring, where the async EOPNOTSUPP completion had no retry path.
Route it through the same sync helpers that the other engines
already use.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
In case the host MAC address associated with a TAP device wasn't
explicitly provided by the user, Cloud Hypervisor would get the host MAC
associated by default with this TAP device and store it through the
network config. Problem is, in the context of a snapshot/restore, that
meant the network config provided by the user was different on the
destination host compared to the source host. This was causing an issue
when Cloud Hypervisor wasn't started with CAP_NET_ADMIN permissions as
it couldn't set the host MAC address on the destination, while the
source never needed these permissions since the MAC was automatically
allocated by the kernel.
We're fixing this issue by setting the host MAC address when it's
explicitly requested by the user through the network config, and making
the host MAC immutable so that it can't be changed at runtime.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Further stability improvements in the villain harness keep printed
verdicts when a batch times out, stop batch timeouts from wedging
benign tests, and capture VMM stderr separately so it cannot
corrupt verdict markers, reducing spurious WEDGED results.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add sparse region support to remote live migration as it will save some
of the network bandwidth and therefore speed up the migration to the
destination VM.
Instead of sending the entire guest RAM over the network, only send
ranges which have been populated during the first iteration. Pages full
of holes are simply skipped.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-8
A PCI BAR stores its address in the upper bits and type information in
the lower bits. To determine the BAR size, an operating system disables
memory decoding, writes ones to the BAR's address bits, and reads the
value back. Bits that remain zero reveal the required alignment and
therefore the size.
We currently recognize only 0xffffffff as a size probe. OpenBSD instead
writes the memory BAR address mask 0xfffffff0, without setting the lower
four non-address bits [0][1].
We misinterpret that probe as a real BAR relocation. Because OpenBSD has
disabled memory space, the relocation remains pending. We apply it when
OpenBSD enables memory space again, moving the virtio block BAR away
from its mapped address and preventing the guest from booting.
Recognize probes using the address mask for each BAR type and exclude
them from BAR reprogramming. Add a test for the OpenBSD memory BAR
probe.
[0]: 54a2bc1e54/sys/dev/pci/pci_map.c (L154-L180)
[1]: 54a2bc1e54/sys/dev/pci/pcireg.h (L429-L443)
Co-authored-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
On-behalf-of: SAP leander.kohler@sap.com
Signed-off-by: Leander Kohler <leander.kohler@cyberus-technology.de>
Both tests intermittently report WEDGED because the villain harness
can lose the guest verdict marker when the VM exits before the VMM
drains the console virtqueue, so the host reads a console with no
marker under load. This is a harness race, not a CH defect, and it
lands on a random test each run. Exclude the two most affected
until the harness drains the console on shutdown.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
After churning a single L2 region with an fsync per write, close and
reopen the image. parse_qcow rebuilds the free list from the on disk
refcounts, so a reopen that recovers many clusters means the runtime
allocator stranded them. Without the fix the reopen recovered every
relocated cluster. Now it finds none.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
After churning a single L2 region with an fsync per write, scan the file
for refcount==0 clusters and assert every one is on the runtime free
list. The reuse bug left relocated refcount block clusters free on disk
but off the list, so this fails without the fix, reporting the exact
count of stranded clusters.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add a regression test that churns one L2 region with an fsync per write,
relocating the L2 table and its refcount block every iteration, and
asserts committed host blocks track live data instead of doubling. Data
written across the churn is read back to confirm integrity.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Metadata tables use relocate on write. The first modification after a
flush writes the table to a new cluster and frees the old one. The L2
path returns the old cluster to the free list, but the refcount block
path did not. QcowState::set_cluster_refcount set the dropped refcount
block cluster to refcount 0 yet never pushed it onto unref_clusters, so
it stayed committed on the host and was invisible to the allocator.
Every refcount block relocation stranded one cluster, and
get_new_cluster extended the file instead of reusing it.
Under a sync heavy workload each fsync that dirties a table relocates
it, so the physical footprint grew at roughly twice the live data
without bound. qemu-img check stayed clean because the refcounts are
correct, and a reopen, which rebuilds the free list from refcounts,
recovered the space.
Push the dropped refcount block cluster onto unref_clusters so the
running allocator reuses it, matching the L2 table path.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add a live migration section to the VFIO documentation covering the
requirements beyond snapshot and restore, the dirty tracking behavior,
the destination file descriptor substitution with an example, and the
failure recovery behavior. Link it from the live migration and
snapshot sections.
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
The VmConfig that arrives over the migration stream carries the
source's device paths and stale FDs, none of which are usable on the
destination. A received VFIO device therefore needs fresh descriptors
supplied with the request.
VmReceiveMigrationData gains vfio_fds, pairing each device id with a
cdev FD, and iommufd_fd for the backing iommufd, both arriving over
SCM_RIGHTS. Once the received VmConfig is available, each named
device's path or FD is swapped for the received one and the iommufd is
installed before the VM is built, so the device comes up FD backed.
The request is rejected when a substituted device lacks the iommufd
backend, when an id is unknown or repeated, or when a device names no
replacement in vfio_fds. These checks run against the migrated VmConfig
once it has been received.
ch-remote gains the vfio_fds and iommufd_fd options and forwards the
descriptors over SCM_RIGHTS. The D-Bus transport cannot carry file
descriptors and drops them.
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
A VFIO device restored onto a different host has a device path and
iommufd that are meaningless there, and an FD backed device cannot
serialize a live descriptor into the snapshot at all. Restoring one
therefore needs fresh descriptors supplied with the request.
RestoreConfig gains vfio_fds, pairing each device id with a cdev FD,
and iommufd_fd for the backing iommufd. Both arrive over SCM_RIGHTS on
the restore request. vm_restore swaps each named device's stale path
or FD for the received one and installs the iommufd before the VM is
built, so the device comes up FD backed.
The request is rejected when a substituted device lacks the iommufd
backend, when an id is unknown or repeated, or when an FD backed device
names no replacement.
ch-remote gains the vfio_fds and iommufd_fd options and forwards the
descriptors through the SCM_RIGHTS pool.
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
Wire the previously empty Migratable implementation on VfioPciDevice to
VFIO DMA logging so the pages the device writes to guest memory are
tracked during a live migration. The Vfio trait gains the DMA logging
operations with defaults that report no migration support.
Without a virtual IOMMU the device sees an identity mapping of guest
memory, so the tracked ranges are the guest memory regions with iova
equal to gpa. The requested page size is only a hint, so the device
reports back the granularity it actually applied.
A device that does not support migration, or one behind a virtual
IOMMU, is refused at migration start rather than silently skipping
dirty tracking and producing an incorrect log. Under a virtual IOMMU
the reported IOVAs are not guest addresses and the logged range set
would have to track the mapping changes a guest makes mid migration,
so that configuration is out of scope.
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
A failed VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE set can leave the device
in its original state, midway along a combination transition, or in
ERROR. The uAPI leaves recovery to the user, and from ERROR only a
VFIO_DEVICE_RESET brings the device back to RUNNING.
Previously a failed transition left the device wherever it landed, so
one that reached ERROR stayed wedged for the life of the guest even
though a reset would have recovered it.
On a failed transition the caller now names an optional recovery state
to attempt first, falling back to a device reset. Pause, resume, and
the return to STOP after STOP_COPY name no recovery state, so their
failure resets directly. The original transition error is always
propagated and recovery failures are logged.
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
The S0094 state test could be reported as WEDGED when the host per
test timeout killed the VM before the guest finished its wait,
dropping the verdict marker. v0.5.2 accepts that timeout case as a
pass since the device does not consume the buffer before DRIVER_OK.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace the QEMU debugger VM approach with a simpler setup that runs
WinDbg directly on a Windows host. Cloud Hypervisor exposes the guest
serial port on a UNIX socket, socat turns it into a TCP listener, and
the convey tool bridges the TCP endpoint to a named pipe that WinDbg
attaches to.
This drops the need for a second Windows VM and the socat SYSTEM shell
script wrapping.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add a GitHub Actions job that runs the virtio-villain suite against
cloud-hypervisor, giving continuous coverage of how the virtio device
model responds to guest input that violates the driver side rules of
the virtio specification. The suite drives the device model from the
guest side with out of spec virtqueue input, malformed descriptor
chains, transport register abuse, and device specific requests, then
checks that each violation is handled without crashing the device or
leaving it wedged. This makes a class of guest triggered failures a
signal that shows up on every relevant change rather than found by
chance.
The job builds cloud-hypervisor with the kvm feature, clones
virtio-villain at a pinned tag, builds its initramfs, and runs the
tests in short lived VMs, rerunning a wedged batch in isolation so a
failure is attributed to the offending test. Results reach the run
summary page, and the JUnit report plus per test logs upload as an
artifact. The compiled harness, the initramfs, and the fetched guest
kernel are cached under the resolved villain commit, so an unchanged
pin skips the rebuild.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Assisted-by: Claude:Opus-4.8
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace the hard-coded KVM SNP page type constants with the
KVM_SEV_SNP_PAGE_TYPE_* values from kvm-bindings.
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
KVM builds the VMSA internally, so the logic in igvm-loader passing a
VMSA page for KVM is misleading. The page is silently dropped later
in import_isolated_pages(). Only MSHV actually imports it.
Make PageTypeConfig::vmsa an Option that is None on KVM and push the
VMSA page only when it is set. As KVM no longer produces a VMSA page,
remove the now-dead skip in import_isolated_pages().
Signed-off-by: Ruben Hakobyan <hruben@meta.com>