mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: memory_manager: add on-demand snapshot restore via userfaultfd
When memory_restore_mode=ondemand is specified on the restore command, the memory manager creates a userfaultfd descriptor, registers each guest RAM range for missing-page fault interception, and spawns a handler thread that serves page faults from the snapshot file using UFFDIO_COPY. This avoids reading the entire memory-ranges file into guest RAM before restore completes. The handler uses epoll to multiplex the userfaultfd and a stop eventfd for clean shutdown. Concurrent faults from multiple vCPUs are handled by treating EEXIST as a benign race and waking blocked threads with UFFDIO_WAKE. Once all pages have been served the handler exits automatically. If the handler thread panics the VMM is signalled to exit since the VM cannot continue without page fault service. MemoryZone gains a backing_page_size field so the handler resolves fault granularity from the zone rather than the top-level config. Errors from the UFFD setup path use a structured UffdError enum and a new MigratableError::OnDemandRestore variant, with a From impl to keep call sites concise. The seccomp filter is updated to allow the userfaultfd syscall and the four uffd ioctls (UFFDIO_API, UFFDIO_COPY, UFFDIO_REGISTER, UFFDIO_WAKE) under the VMM thread profile. Signed-off-by: Shayon Mukherjee <shayonj@gmail.com>
This commit is contained in:
committed by
Rob Bradford
parent
bf85af907e
commit
c417924a29
+21
-10
@@ -51,7 +51,7 @@ use crate::api::{
|
||||
ApiRequest, ApiResponse, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
|
||||
VmSendMigrationData, VmmPingResponse,
|
||||
};
|
||||
use crate::config::{RestoreConfig, add_to_config};
|
||||
use crate::config::{MemoryRestoreMode, RestoreConfig, add_to_config};
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use crate::coredump::GuestDebuggable;
|
||||
use crate::landlock::Landlock;
|
||||
@@ -88,6 +88,8 @@ mod pci_segment;
|
||||
pub mod seccomp_filters;
|
||||
mod serial_manager;
|
||||
mod sigwinch_listener;
|
||||
mod uffd;
|
||||
mod userfaultfd;
|
||||
pub mod vm;
|
||||
pub mod vm_config;
|
||||
|
||||
@@ -1506,6 +1508,7 @@ impl Vmm {
|
||||
source_url: &str,
|
||||
vm_config: Arc<Mutex<VmConfig>>,
|
||||
prefault: bool,
|
||||
memory_restore_mode: MemoryRestoreMode,
|
||||
) -> std::result::Result<(), VmError> {
|
||||
let snapshot = recv_vm_state(source_url).map_err(VmError::Restore)?;
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
@@ -1548,6 +1551,7 @@ impl Vmm {
|
||||
Some(&snapshot),
|
||||
Some(source_url),
|
||||
Some(prefault),
|
||||
Some(memory_restore_mode),
|
||||
)?;
|
||||
self.vm = Some(vm);
|
||||
|
||||
@@ -1754,6 +1758,7 @@ impl RequestHandler for Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
|
||||
self.vm = Some(vm);
|
||||
@@ -1838,17 +1843,22 @@ impl RequestHandler for Vmm {
|
||||
}
|
||||
}
|
||||
|
||||
self.vm_restore(source_url, vm_config, restore_cfg.prefault)
|
||||
.map_err(|vm_restore_err| {
|
||||
error!("VM Restore failed: {vm_restore_err:?}");
|
||||
self.vm_restore(
|
||||
source_url,
|
||||
vm_config,
|
||||
restore_cfg.prefault,
|
||||
restore_cfg.memory_restore_mode,
|
||||
)
|
||||
.map_err(|vm_restore_err| {
|
||||
error!("VM Restore failed: {vm_restore_err:?}");
|
||||
|
||||
// Cleanup the VM being created while vm restore
|
||||
if let Err(e) = self.vm_delete() {
|
||||
return e;
|
||||
}
|
||||
// Cleanup the VM being created while vm restore
|
||||
if let Err(e) = self.vm_delete() {
|
||||
return e;
|
||||
}
|
||||
|
||||
vm_restore_err
|
||||
})
|
||||
vm_restore_err
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
@@ -1930,6 +1940,7 @@ impl RequestHandler for Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
|
||||
// And we boot it
|
||||
|
||||
Reference in New Issue
Block a user