Skip to content

Commit 5b3708f

Browse files
committed
Snapshot restore for swiotlb regions
Support restoring VMs with swiotlb regions. For this, untangle the uffd handshake from the actual restoration of memory regions, as we first need to restore and register to the Vm _all_ memory regions, before we can then send a single handshake containing both normal and swiotlb regions to the Uffd handler. While we're here, significantly simplify the jungle of error types. Signed-off-by: Patrick Roy <[email protected]>
1 parent 3196935 commit 5b3708f

File tree

10 files changed

+178
-197
lines changed

10 files changed

+178
-197
lines changed

src/vmm/src/arch/aarch64/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ use crate::cpu_config::templates::CustomCpuTemplate;
3030
use crate::initrd::InitrdConfig;
3131
use crate::utils::{align_up, usize_to_u64};
3232
use crate::vmm_config::machine_config::MachineConfig;
33-
use crate::vstate::memory::{
34-
Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap,
35-
};
33+
use crate::vstate::memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
3634
use crate::vstate::vcpu::KvmVcpuError;
3735
use crate::{Vcpu, VcpuConfig, Vmm};
3836

@@ -118,7 +116,9 @@ pub fn configure_system_for_boot(
118116

119117
let swiotlb_region = match vmm.vm.swiotlb_regions().num_regions() {
120118
0 | 1 => vmm.vm.swiotlb_regions().iter().next(),
121-
_ => panic!("Firecracker tried to configure more than one swiotlb region. This is a logic bug.")
119+
_ => panic!(
120+
"Firecracker tried to configure more than one swiotlb region. This is a logic bug."
121+
),
122122
};
123123

124124
let fdt = fdt::create_fdt(

src/vmm/src/builder.rs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
//! Enables pre-boot setup, instantiation and booting of a Firecracker VMM.
55
66
use std::fmt::Debug;
7-
use std::io;
7+
use std::io::{self};
88
#[cfg(feature = "gdb")]
99
use std::sync::mpsc;
1010
use std::sync::{Arc, Mutex};
1111

1212
use event_manager::{MutEventSubscriber, SubscriberOps};
1313
use libc::EFD_NONBLOCK;
1414
use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
15-
use userfaultfd::Uffd;
1615
use utils::time::TimestampUs;
16+
use vm_memory::GuestMemoryRegion;
1717
#[cfg(target_arch = "aarch64")]
1818
use vm_superio::Rtc;
1919
use vm_superio::Serial;
@@ -50,14 +50,17 @@ use crate::devices::virtio::vsock::{Vsock, VsockUnixBackend};
5050
use crate::gdb;
5151
use crate::initrd::{InitrdConfig, InitrdError};
5252
use crate::logger::{debug, error};
53-
use crate::persist::{MicrovmState, MicrovmStateError};
53+
use crate::persist::{
54+
MicrovmState, MicrovmStateError, RestoreMemoryError, SnapshotStateFromFileError,
55+
restore_memory, send_uffd_handshake,
56+
};
5457
use crate::resources::VmResources;
5558
use crate::seccomp::BpfThreadMap;
5659
use crate::snapshot::Persist;
5760
use crate::vmm_config::instance_info::InstanceInfo;
5861
use crate::vmm_config::machine_config::MachineConfigError;
62+
use crate::vmm_config::snapshot::{MemBackendConfig, MemBackendType};
5963
use crate::vstate::kvm::Kvm;
60-
use crate::vstate::memory::GuestRegionMmap;
6164
use crate::vstate::vcpu::{Vcpu, VcpuError};
6265
use crate::vstate::vm::Vm;
6366
use crate::{EventManager, Vmm, VmmError, device_manager};
@@ -393,6 +396,8 @@ pub enum BuildMicrovmFromSnapshotError {
393396
SetTsc(#[from] crate::arch::SetTscError),
394397
/// Failed to restore microVM state: {0}
395398
RestoreState(#[from] crate::vstate::vm::ArchVmError),
399+
/// Failed to get snapshot state from file: {0}
400+
LoadState(#[from] SnapshotStateFromFileError),
396401
/// Failed to update microVM configuration: {0}
397402
VmUpdateConfig(#[from] MachineConfigError),
398403
/// Failed to restore MMIO device: {0}
@@ -413,19 +418,19 @@ pub enum BuildMicrovmFromSnapshotError {
413418
ACPIDeviManager(#[from] ACPIDeviceManagerRestoreError),
414419
/// VMGenID update failed: {0}
415420
VMGenIDUpdate(std::io::Error),
421+
/// Failed to restore guest memory: {0}
422+
Memory(#[from] RestoreMemoryError),
416423
}
417424

418425
/// Builds and starts a microVM based on the provided MicrovmState.
419426
///
420427
/// An `Arc` reference of the built `Vmm` is also plugged in the `EventManager`, while another
421428
/// is returned.
422-
#[allow(clippy::too_many_arguments)]
423429
pub fn build_microvm_from_snapshot(
424430
instance_info: &InstanceInfo,
425431
event_manager: &mut EventManager,
426432
microvm_state: MicrovmState,
427-
guest_memory: Vec<GuestRegionMmap>,
428-
uffd: Option<Uffd>,
433+
mem_backend: &MemBackendConfig,
429434
seccomp_filters: &BpfThreadMap,
430435
vm_resources: &mut VmResources,
431436
) -> Result<Arc<Mutex<Vmm>>, BuildMicrovmFromSnapshotError> {
@@ -439,11 +444,63 @@ pub fn build_microvm_from_snapshot(
439444
)
440445
.map_err(StartMicrovmError::Internal)?;
441446

447+
let track_dirty_pages = vm_resources.machine_config.track_dirty_pages;
448+
let huge_pages = vm_resources.machine_config.huge_pages;
449+
450+
let mem_backend_path = &mem_backend.backend_path;
451+
452+
let mem_file = match mem_backend.backend_type {
453+
MemBackendType::File => Some(mem_backend_path),
454+
MemBackendType::Uffd => None,
455+
};
456+
457+
let guest_memory = restore_memory(
458+
&microvm_state.vm_state.memory,
459+
mem_file,
460+
huge_pages,
461+
track_dirty_pages,
462+
0,
463+
)?;
464+
let io_memory = restore_memory(
465+
&microvm_state.vm_state.io_memory,
466+
mem_file,
467+
huge_pages,
468+
track_dirty_pages,
469+
guest_memory.iter().map(|r| r.len()).sum(),
470+
)?;
471+
442472
vmm.vm
443473
.register_memory_regions(guest_memory)
444474
.map_err(VmmError::Vm)
445475
.map_err(StartMicrovmError::Internal)?;
446-
vmm.uffd = uffd;
476+
477+
for region in io_memory {
478+
vmm.vm
479+
.register_swiotlb_region(region)
480+
.map_err(VmmError::Vm)
481+
.map_err(StartMicrovmError::Internal)?;
482+
}
483+
484+
vmm.uffd = match mem_backend.backend_type {
485+
MemBackendType::File => None,
486+
MemBackendType::Uffd => {
487+
let (uffd, mut mappings) = vmm
488+
.vm
489+
.create_uffd()
490+
.map_err(RestoreMemoryError::UffdCreate)?;
491+
492+
#[allow(deprecated)]
493+
mappings.iter_mut().for_each(|mapping| {
494+
mapping.page_size = vm_resources.machine_config.huge_pages.page_size();
495+
mapping.page_size_kib = vm_resources.machine_config.huge_pages.page_size();
496+
});
497+
498+
send_uffd_handshake(mem_backend_path, &mappings, &uffd)
499+
.map_err(RestoreMemoryError::UffdHandshake)?;
500+
501+
Some(uffd)
502+
}
503+
};
447504

448505
#[cfg(target_arch = "x86_64")]
449506
{

src/vmm/src/devices/virtio/vhost_user.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ pub(crate) mod tests {
478478
libc::MAP_PRIVATE,
479479
Some(file),
480480
false,
481+
0,
481482
)
482483
.unwrap()
483484
.into_iter()

0 commit comments

Comments
 (0)