When the receiver of a live migration encounters an error, it sends an
error response. The sender of the migration would then send an abandon
request and wait for a response. This abandon request is not necessary,
because the receiver already abandoned the migration due to the error it
encountered.
From now on this function will not send an abandon request to the
receiver anymore, thus it was renamed to "ok_or_error".
Also, this case was always broken, because after sending the error
response, the receiver just exits without waiting for the additional
abandon request.
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
Receiving a migration happens inside the VMM thread, which blocks the
API until a migration was received. On the other hand, sending a
migration is actually just a dispatch operation. We adjust the wording
to improve clarity of the error messages.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On the receiver side, a live migration with status "aborted" does not
return an error. Thus, management software will think that the live
migration was successful (from just looking at the API response). This
is not expected behaviour.
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
So far, we only have seccomp rules for the postcopy-send thread. This
commit introduces the basic plumbing to add seccomp rules also for the
migration worker (the migration coordinator) as well as the TCP workers
(both, send and receive) in the following.
To streamline code setup, all filters are created at a central place
early in the migration code. Although this means that some filters are
created without the need to do so (e.g., postcopy), this massively
simplifies code setup and error handling. This overhead is negligible.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
ReceiveAdditionalConnections got quite complicated, especially with the
many threads involved for precopy and the special-case of postcopy. We
therefore should add comprehensive documentation.
I tried to keep it short and concise - what remains provides high value
and improves the mental model of the code.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
Live migration can deadlock if the guest triggers a virtio device
activation while the migration worker owns the VM.
The failure shows up when starting live migrations during boot and
firmware startup, where the guest can reset and reinitialize virtio
devices while precopy is running. In the failing case, the source log
shows a pending virtio activation that never completes:
8.115833s _virtio-pci-net_0: Needs activation; returning barrier
8.115854s vmm/src/vm.rs:464 -- Waiting for barrier
24.875452s Entering downtime phase
24.875481s stopping vcpu throttling thread
...
vCPU thread did not respond in 10ms to signal - retrying
vCPU thread did not respond in 20ms to signal - retrying
...
thread 'throttle-vcpu' (1029) panicked
...
Pause(Error signalling vCPUs: Timeout when waiting for signal
to be acknowledged)
The vCPU blocks on the activation barrier and never reaches the normal
pause checkpoint. Later, migration enters downtime and stops the vCPU
throttle thread. In the failing case, that thread is still inside a
CpuManager::pause() call, which waits for every vCPU to acknowledge
the signal. The blocked vCPU never does, so the pause times out.
Fix this by storing the DeviceManager inside VmOwnership::Migration.
This keeps just enough state on the VMM thread to drain pending virtio
activations while the migration worker owns the Vm. The barrier logic
stays unchanged. The VMM now releases the same activation barrier during
migration that it already released before migration started.
This keeps the guest from getting stuck in the activation wait and
lets the later pause succeed.
Co-authored-by: Leander Kohler <leander.kohler@cyberus-technology.de>
On-behalf-of: SAP leander.kohler@sap.com
Signed-off-by: Leander Kohler <leander.kohler@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
When seccomp traps a SIGSYS, print the syscall number that caused it,
the current thread id and thread name to make violations easier to
debug.
This change requires that all threads are allowed to execute the
`gettid` and the `prctl` syscalls, thus the seccomp filters have also
been adjusted.
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
In [0] we agreed on the current format. When ch-remote or
cloud-hypervisor exit with an error, they nicely print the whole chain.
This, however, doesn't work when simply doing `error!("error: {e}")`
- which is what we currently do for migration-related errors.
This commit walks the chain of errors and prints all components in a
single line. This massively improves the quality of error messages and
helps tracing down where an error is originating from. Using ` => ` as
separator is better than `\n` which doesn't work well in our current
log format.
# Example (Before - Bad)
```
cloud-hypervisor: 2.859287s: <vmm> ERROR:vmm/src/lib.rs:2021 -- Migration failed: Failed to send migratable component snapshot
```
# Example (New - Better)
```
cloud-hypervisor: 2.296160s: <vmm> ERROR:vmm/src/lib.rs:2038 -- Migration failed: Failed to send migratable component snapshot => Error connecting to TCP socket => Connection refused (os error 111)
```
[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7066
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
Keep the original error sources while adding operation context to the
straightforward migration send and receive paths. This keeps up a
chain of errors that can be printed nicely and in a helpful way.
This commit does that for all MigratableError-occurences where this
change is easily applicable.
Co-authored-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
size_of is part of std::prelude as of Rust 1.80 (with size_of_val,
align_of, align_of_val), and the workspace MSRV is 1.89, so qualifying
it (mem::size_of, std::mem::size_of, core::mem::size_of) is unnecessary.
Convert every qualified size_of call-site to the bare prelude form and
drop the now-redundant `use std::mem::size_of;` imports, keeping
`use std::mem;` where it still serves non-prelude items (transmute,
swap, replace, take, zeroed, MaybeUninit, offset_of). size_of is the
only one of the four currently used in the tree.
Pure refactor, no behavioural change. Follow-up to the
clippy::absolute_paths cleanup (#7670), as discussed in #8444.
Signed-off-by: Henry Hrvoje Tonkovac <htonkovac@gmail.com>
Assisted-by: Claude:Opus-4.8
Import the modules used in the crate instead of spelling the full paths
at every use site, and drop the now-unnecessary crate-level
Signed-off-by: Henry Hrvoje Tonkovac <htonkovac@gmail.com>
Assisted-by: Claude:Opus-4.8
We have larger cloud deployments and analyzed the logs. Let's silence
some messages that generally provide little value on the `info!` level.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
Applying seccomp filtering to the migration postcopy thread running on
the source VM during migration.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-8
Wire up the source side of postcopy migration over TCP. When
`mode=postcopy` is requested on vm.send-migration, the source skips
the pre-copy dirty-tracking loop and lets the destination resume early,
then serves guest pages on demand over a dedicated connection.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Plumb the SocketUffdMemorySource into the receiving side of live
migration. When memory_mode=postcopy is requested, the destination
brings up a dedicated fault connection, registers userfaultfd on the
restored memory regions, and serves guest pages on demand over that
connection while the VM resumes early.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Add the socket-backed UffdMemorySource that resolves each fault by
sending a Command::PageFault request to the peer over a dedicated fault
connection.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Introducing a migration mode to both sides of the migration (send and
receive), so that a user can desribe which way the memory should be
migrated between the source and destination VMs.
For now, we only introduce `precopy` and `postcopy` as viable options,
but we can expect other modes (more optimized) to be added in the
future.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-8
Extract the page content provider out of the userfaultfd handler so it
can be plugged with different backends in followup commits.
No functional change intended.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Restoring a snapshot (snapshot restore or live-migration receive) sets
each vCPU's TSC by writing MSR_IA32_TSC as the vCPU is created.
However because CpuManager creates and restores vCPUs one at a time, the
host TSC advances between the per-vCPU writes and KVM derives a slightly
different TSC offset for each vCPU.
KVM only engages its masterclock when every offset matches. This has a
side effect of breaking the HyperV TSC reference clock page resulting in
significantly reduced performance on Windows.
After restore synchronise all vCPU's TSC offset to the boot vCPU's via
the KVM_VCPU_TSC_CTRL device attribute group (Linux 5.16+) this allows
the KVM TSC masterclock to engage and mitigates performance issues with
the KVM HyperV emulation.
See: #8383
Signed-off-by: Rob Bradford <rbradford@meta.com>
Assisted-by: Claude <claude-opus-4-8>
This puts the send-migration action into a dedicated thread, laying the
groundwork for many follow-ups towards first-class live-migration in
CH.
This means:
1. The send-migration call will exit sooner (just trigger the
migration - dispatch semantics)
2. Other API calls can be triggered while a migration is ongoing but
will not be able to alter the VM as the VM's ownership is transferred
from the VMM to the migration thread. Example: hotplugging won't work
(which is good).
3. This is the basis for migration statistics via a dedicated endpoint
(future work).
The whole change was done with a special focus on graceful recover and
cleanup: even if anything on the migration paths go wrong, the proper
cleanups are already executed and the VMM can take back the ownership
of the VM.
The receive-migration API call remains blocking. To observe any status
changes about the migration on the sender side, one can observe the
event-monitor output and look for `vm.migration-{failed,finished}`.
These changes are inspired by [0] but differ significantly in details.
[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7038
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This initializes the module and the thread that will handle (control)
the migration. This introduces the new types without the necessary
wiring.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This was already handled with user memory zones but not with the default
memory. Make a small refactoring to move the boot RAM check into
MemoryManager rather than split across Vm and MemoryManager.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Currently, Cloud Hypervisor round-trips CNTVCT_EL0 through
KVM_GET_REG_LIST/SET_ONE_REG, which leaves a cold-restored or migrated
guest behind real UTC by the downtime. Same-host pause/resume
self-corrects (the physical counter keeps running across the pause), so
only restore and migration cases required the clock to catch up to wall
clock time.
Since ARM has no kernel helper, compute the difference in wall clock
time and compute the ticks so that it can advance the CNTVCT correctly.
It is set via vcpu0 only as it affects a single VM wide value after
Linux 6.4. For older kernels, it was a truly vcpu value which needs to
be invoked for every vcpu.
Gated on all(target_arch = "aarch64", feature = "kvm"); x86 is
unchanged.
Basic manual test case (aarch64 + KVM) verified both in intra host and
inter host snapshot save/restore:
1. Boot a Linux guest; in the guest, `date -u` tracks the host's UTC.
2. Pause and snapshot the VM (ch-remote pause; ch-remote snapshot
file:///<dir>).
3. Leave it down for several minutes (the off-host interval).
4. Restore and resume into a fresh VMM (ch-remote restore
source_url=file:///<dir>,resume=true).
5. In the guest, run `date -u` again and compare to the host: the guest
now tracks current UTC, having advanced by ~the time it spent down.
Before this change the restored guest reads behind real UTC by the
downtime; after it, the guest clock is back in sync (to within the
snapshot-to-restore sampling slop).
Signed-off-by: Atish Patra <atishp@meta.com>
Unlike x86, ARM64 has no kvmclock support to sync guest time upon
required. However, the guest reads the architected virtual timer
(CNTVCT_EL0) directly which can be modified by the VMM to update the
time after snapshot restore. Since the CNTVCT is in ticks, we also need
to read CNTFRQ (via mrs due to lack of ONEREG interface) to compute the
ticks from wall clock difference.
Because the counter is a vCPU register, the capture must run with the
vCPUs quiesced, so the VMM now captures the clock just after
cpu_manager.pause() through the boot vCPU. This is behaviorally
identical for x86, whose clock is VM-wide. There is no restore/advance
yet, so aarch64 guests still resume behind real time until the following
commit.
Signed-off-by: Atish Patra <atishp@meta.com>
Currently, VM pause/resume/snapshot paths invoke architecture specific
bits for guest clock udpates which ideally belongs to hypervisor layer.
Route it through the snapshot_clock()/restore_clock() pair added in the
previous commit instead, so the VMM no longer depends on an architecture
specific clock API and the upcoming aarch64 backend can hook the same
path without a parallel branch in vm.rs.
Signed-off-by: Atish Patra <atishp@meta.com>
OpenBSD expects the ACPI _S5_ object to provide both sleep type values.
The single-value package made acpi_init_states() parse an invalid object
and fault during early ACPI setup with:
```
...
acpi0 at bios0: ACPI 6.3
acpi0: sleep statesfatal protection fault in supervisor mode
trap type 4 code 0 rip ffffffff814af264 cs 8 rflags 10282 cr2 0 cpl e rsp ffffffff81a06a30
gsbase 0xffffffff81755ff0 kgsbase 0x0
panic: trap type 4, code=0, pc=ffffffff814af264
Starting stack trace...
panic(ffffffff81a06980,4,ffffffff81a06a58,ffffffff81756ae0,ffffffff81a06960,ffffffff81a068e0) at panic+0x12e
kerntrap(ffffffff81a06aa0,ffff800000232400,ffffffff81261681,ffffffff81a06970,ffffffff81a06980,4) at kerntrap+0xe1
alltraps_kern_meltdown(4,ef0d316e102be1f4,ffff800000232480,0,ffffffff81a06aa0,ffff800000232400) at alltraps_kern_meltdown+0x7b
aml_val2int(ef0d316e102be1f4,0,10,ffffffff81a06a30,10282,8) at aml_val2int+0x24
acpi_init_states(1,ffff800000232400,ffff800000232470,0,ef0d316e102be1f4,5f35535f) at acpi_init_states+0xd5
acpi_attach_common(ffff800000235300,ffffffff81a06cf0,ffffffff81762a00,ffff800000232400,ffff800000232424,ef0d316e102be1f4) at acpi_attach_common+0x311
config_attach(ffffffff81a06d30,ffff800000235300,50,118,ffff80003158c004,ffffffff813e3270) at config_attach+0x1d2
bios_attach(ffff800000235280,ffffffff81a06e28,ffffffff8175ca50,ffff800000235300,ffff800000235324,ef0d316e102be1f4) at bios_attach+0x898
config_attach(ffffffff81a06e28,ffff800000235280,ffffffff81757e68,ffff800000235280,ffff8000002352a4,ffffffff8128c510) at config_attach+0x1d2
mainbus_attach(0,0,ef0d316e102be1f4,ffffffff81a06e50,ffffffff81a06ec0,3000000010) at mainbus_attach+0x70
config_attach(8,1001000,805f50,1000000,ffffffff81a00008,0) at config_attach+0x1d2
cpu_configure(8,1001000,ffffffff814f3859,ffffffff81a06f20,8,1001000) at cpu_configure+0x29
main(1001000,ef0d316e102be1f4,ffffffff812e8b2f,ffffffff81a06f40,8,1001000) at main+0x3af
end trace frame: 0x0, count: 244
End of stack trace.
```
Advertise S5 as the conventional four-element package as described in
the ACPI spec [1]. Cover the generated AML bytes with a unit test.
In AML, the package now looks like this:
```
Name (_S5, Package () {
0x05, 0x05, 0x00, 0x00
})
```
[1] https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/07_Power_and_Performance_Mgmt/oem-supplied-system-level-control-methods.html#sx-system-states
On-behalf-of: SAP thomas.prescher@sap.com
Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
Move next_data_extent and write_region_sparse out of memory_manager.rs
into a new vmm::sparse module so the snapshot writer, the restore
reader, and the offload daemon can share one implementation.
No functional change intended.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Expose VmMigrationConfig as a public facing structure that can be used
by an offload daemon to act as if it was the VM to migrate to, or the VM
to migrate from.
Signed-off-by: Sebastien Boeuf <sboeuf@meta.com>
Assisted-by: Claude:claude-opus-4-7
Fix disk hot unplug failure caused by seccomp SIGSYS kill.
When performing disk hot unplug, the vcpu thread calls fsync()
on the block device file descriptor to flush pending I/O.
The seccomp filter previously blocked SYS_fsync, triggering SIGSYS
and terminating the vcpu thread, which makes the hot unplug
operation fail. This issue exists on both x86 and AArch64.
Strace log snippet captured during failure:
```
[pid 3118852] fsync(142) = 142
[pid 3118852] ---SIGSYS {si_signo=SIGSYS,si_code=SYS_SECCOMP,si_call_addr=0xffff9c931df8, si_syscall=__NR_fsync,si_arch=AUDIT_ARCH_AARCH64}
```
Add unrestricted SYS_fsync entry to vcpu thread syscall allowlist,
consistent with existing file I/O syscalls such as fcntl and fstat.
Signed-off-by: yanjianqing <yanjianqing@kylinos.cn>
Reject without asserting that the ACPI CPU hotplug register accesses
match those that are specified by the ACPI definitions.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Assisted-by: Claude:Opus-4.7
Reject without asserting that the ACPI PCI hotplug register request
matches what is defined in the ACPI definition.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Assisted-by: Claude:Opus-4.7
The RISC-V device tree's timebase-frequency was hardcoded to 10 MHz
(0x989680). Actual hardware uses different frequencies.
Read the timebase frequency from KVM_GET_ONE_REG via
KVM_REG_RISCV_TIMER (offset 0, kvm_riscv_timer.frequency),
thread it through the VMM to arch to FDT layers, and fall back to
the 10 MHz default when KVM returns no value.
Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
Removal of absolute paths is currently in progress. To avoid regressing
those changes add a clippy deny at the workspace level and at the crate
level override with #[expect(clippy::absolute_paths)]
See: #7670
Signed-off-by: Rob Bradford <rbradford@meta.com>
The CLI `--platform` option now accepts `iommufd_fd=<n>` alongside the
existing `iommufd=on|off`.
Signed-off-by: Bo Chen <bchen@crusoe.ai>
Assisted-by: Claude:Opus-4.7
`path` is no longer required in the DeviceConfig, since a VFIO
device may also be supplied via a pre-opened cdev FD passed via
SCM_RIGHTS alongside the /vm.add-device request.
Signed-off-by: Bo Chen <bchen@crusoe.ai>
Assisted-by: Claude:Opus-4.7
Add a new `fd: Option<i32>` field to DeviceConfig so a caller can
supply a pre-opened vfio cdev FD (e.g. /dev/vfio/devices/vfioN) in
addition to the existing sysfs path. The CLI `--device` option now
accepts `fd=<n>`, parsed alongside the existing options.
Signed-off-by: Bo Chen <bchen@crusoe.ai>
Assisted-by: Claude:Opus-4.7