diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index b8c123b78..6ab80cbec 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -24,7 +24,7 @@ use vm_memory::guest_memory::FileOffset; use vm_memory::{ mmap::MmapRegionError, Address, Bytes, Error as MmapError, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap, GuestMemoryRegion, - GuestRegionMmap, GuestUsize, MmapRegion, + GuestRegionMmap, GuestUsize, MemoryRegionAddress, MmapRegion, }; use vm_migration::{ Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable, @@ -105,6 +105,9 @@ pub enum Error { /// Failed to virtio-mem resize VirtioMemResizeFail(vm_virtio::mem::Error), + /// Cannot restore VM + Restore(MigratableError), + /// Cannot create the system allocator CreateSystemAllocator, } @@ -350,6 +353,64 @@ impl MemoryManager { Ok(memory_manager) } + pub fn new_from_snapshot( + snapshot: &Snapshot, + fd: Arc, + config: &MemoryConfig, + source_url: &str, + ) -> Result>, Error> { + let memory_manager = MemoryManager::new(fd, config)?; + + let url = Url::parse(source_url).unwrap(); + /* url must be valid dir which is verified in recv_vm_snapshot() */ + let vm_snapshot_path = url.to_file_path().unwrap(); + + if let Some(mem_section) = snapshot + .snapshot_data + .get(&format!("{}-section", MEMORY_MANAGER_SNAPSHOT_ID)) + { + let mem_snapshot: MemoryManagerSnapshotData = + match serde_json::from_slice(&mem_section.snapshot) { + Ok(snapshot) => snapshot, + Err(error) => { + return Err(Error::Restore(MigratableError::Restore(anyhow!( + "Could not deserialize MemoryManager {}", + error + )))) + } + }; + + memory_manager + .lock() + .unwrap() + .guest_memory + .memory() + .with_regions(|index, region| { + let mut memory_region_path = vm_snapshot_path.clone(); + memory_region_path + .push(mem_snapshot.memory_regions[index].backing_file.clone()); + + // Create the snapshot file for the region + let mut memory_region_file = OpenOptions::new() + .read(true) + .open(memory_region_path) + .map_err(|e| Error::Restore(MigratableError::MigrateReceive(e.into())))?; + + region + .read_from( + MemoryRegionAddress(0), + &mut memory_region_file, + region.len().try_into().unwrap(), + ) + .map_err(|e| Error::Restore(MigratableError::MigrateReceive(e.into())))?; + + Ok(()) + })?; + } + + Ok(memory_manager) + } + fn create_ram_region( backing_file: &Option, start_addr: GuestAddress, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 3a2547ceb..4a363c2c6 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -29,7 +29,7 @@ use crate::config::{DeviceConfig, DiskConfig, HotplugMethod, NetConfig, PmemConf use crate::cpu; use crate::device_manager::{get_win_size, Console, DeviceManager, DeviceManagerError}; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; -use crate::migration::{url_to_path, VM_SNAPSHOT_FILE}; +use crate::migration::{url_to_path, vm_config_from_snapshot, VM_SNAPSHOT_FILE}; use crate::{CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID}; use anyhow::anyhow; use arch::{BootProtocol, EntryPoint}; @@ -374,6 +374,43 @@ impl Vm { ) } + pub fn new_from_snapshot( + snapshot: &Snapshot, + exit_evt: EventFd, + reset_evt: EventFd, + vmm_path: PathBuf, + source_url: &str, + ) -> Result { + let (kvm, fd) = Vm::kvm_new()?; + let config = vm_config_from_snapshot(snapshot).map_err(Error::Restore)?; + + let memory_manager = if let Some(memory_manager_snapshot) = + snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID) + { + MemoryManager::new_from_snapshot( + memory_manager_snapshot, + fd.clone(), + &config.lock().unwrap().memory.clone(), + source_url, + ) + .map_err(Error::MemoryManager)? + } else { + return Err(Error::Restore(MigratableError::Restore(anyhow!( + "Missing memory manager snapshot" + )))); + }; + + Vm::new_from_memory_manager( + config, + memory_manager, + fd, + kvm, + exit_evt, + reset_evt, + vmm_path, + ) + } + fn load_initramfs(&mut self, guest_mem: &GuestMemoryMmap) -> Result { let mut initramfs = self.initramfs.as_ref().unwrap(); let size: usize = initramfs