mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: make migration errors more helpful
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>
This commit is contained in:
committed by
Bo Chen
parent
05f026440a
commit
8c71a0d821
122
vmm/src/lib.rs
122
vmm/src/lib.rs
@@ -922,9 +922,10 @@ impl Vmm {
|
||||
) -> result::Result<(u32, File), MigratableError> {
|
||||
if let SocketStream::Unix(unix_socket) = socket {
|
||||
let mut buf = [0u8; 4];
|
||||
let (_, file) = unix_socket.recv_with_fd(&mut buf).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error receiving slot from socket: {e}"))
|
||||
})?;
|
||||
let (_, file) = unix_socket
|
||||
.recv_with_fd(&mut buf)
|
||||
.context("Error receiving slot from socket")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
file.ok_or_else(|| MigratableError::MigrateReceive(anyhow!("Failed to receive socket")))
|
||||
.map(|file| (u32::from_le_bytes(buf), file))
|
||||
@@ -1148,10 +1149,9 @@ impl Vmm {
|
||||
.read_exact(&mut data)
|
||||
.map_err(MigratableError::MigrateSocket)?;
|
||||
|
||||
let vm_migration_config: VmMigrationConfig =
|
||||
serde_json::from_slice(&data).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error deserialising config: {e}"))
|
||||
})?;
|
||||
let vm_migration_config: VmMigrationConfig = serde_json::from_slice(&data)
|
||||
.context("Error deserialising config")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
// Eager prefault populates memory before UFFD is registered, so those
|
||||
// pages never fault and are never served. Reject postcopy+prefault
|
||||
@@ -1179,9 +1179,11 @@ impl Vmm {
|
||||
|
||||
let config = vm_migration_config.vm_config.clone();
|
||||
self.vm_config = Some(vm_migration_config.vm_config);
|
||||
self.console_info = Some(pre_create_console_devices(self).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error creating console devices: {e:?}"))
|
||||
})?);
|
||||
self.console_info = Some(
|
||||
pre_create_console_devices(self)
|
||||
.context("Error creating console devices")
|
||||
.map_err(MigratableError::MigrateReceive)?,
|
||||
);
|
||||
|
||||
if self
|
||||
.vm_config
|
||||
@@ -1192,9 +1194,9 @@ impl Vmm {
|
||||
.landlock_enable
|
||||
{
|
||||
let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
|
||||
apply_landlock(&mut config).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error applying landlock: {e:?}"))
|
||||
})?;
|
||||
apply_landlock(&mut config)
|
||||
.context("Error applying landlock")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
}
|
||||
|
||||
let vm = Vm::create_hypervisor_vm(
|
||||
@@ -1227,11 +1229,8 @@ impl Vmm {
|
||||
Some(&vm_migration_config.memory_manager_data),
|
||||
existing_memory_files,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error creating MemoryManager from snapshot: {e:?}"
|
||||
))
|
||||
})?;
|
||||
.context("Error creating MemoryManager from snapshot")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
Ok(memory_manager)
|
||||
}
|
||||
@@ -1260,27 +1259,37 @@ impl Vmm {
|
||||
socket
|
||||
.read_exact(&mut data)
|
||||
.map_err(MigratableError::MigrateSocket)?;
|
||||
serde_json::from_slice(&data).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error deserialising snapshot: {e}"))
|
||||
})
|
||||
serde_json::from_slice(&data)
|
||||
.context("Error deserialising snapshot")
|
||||
.map_err(MigratableError::MigrateReceive)
|
||||
})?;
|
||||
|
||||
let exit_evt = self.exit_evt.try_clone().map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error cloning exit EventFd: {e}"))
|
||||
})?;
|
||||
let reset_evt = self.reset_evt.try_clone().map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error cloning reset EventFd: {e}"))
|
||||
})?;
|
||||
let guest_exit_evt = self.guest_exit_evt.try_clone().map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error cloning guest exit EventFd: {e}"))
|
||||
})?;
|
||||
let exit_evt = self
|
||||
.exit_evt
|
||||
.try_clone()
|
||||
.context("Error cloning exit EventFd")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
let reset_evt = self
|
||||
.reset_evt
|
||||
.try_clone()
|
||||
.context("Error cloning reset EventFd")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
let guest_exit_evt = self
|
||||
.guest_exit_evt
|
||||
.try_clone()
|
||||
.context("Error cloning guest exit EventFd")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let debug_evt = self.vm_debug_evt.try_clone().map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error cloning debug EventFd: {e}"))
|
||||
})?;
|
||||
let activate_evt = self.activate_evt.try_clone().map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error cloning activate EventFd: {e}"))
|
||||
})?;
|
||||
let debug_evt = self
|
||||
.vm_debug_evt
|
||||
.try_clone()
|
||||
.context("Error cloning debug EventFd")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
let activate_evt = self
|
||||
.activate_evt
|
||||
.try_clone()
|
||||
.context("Error cloning activate EventFd")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
let (vm, restore_duration) = measure_ok(|| {
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
@@ -1585,9 +1594,8 @@ impl Vmm {
|
||||
profile,
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error generating common cpuid': {e:?}"))
|
||||
})?
|
||||
.context("Error generating common cpuid")
|
||||
.map_err(MigratableError::MigrateSend)?
|
||||
};
|
||||
|
||||
if send_data_migration.local {
|
||||
@@ -1671,20 +1679,15 @@ impl Vmm {
|
||||
let guest_memory = vm.guest_memory();
|
||||
// Build the seccomp filter on the parent thread so any failure aborts
|
||||
// the migration before the serve thread is spawned.
|
||||
let seccomp_filter = get_seccomp_filter(
|
||||
seccomp_action,
|
||||
Thread::MigrateSendPostcopy,
|
||||
None,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("creating postcopy serve seccomp filter: {e}"))
|
||||
})?;
|
||||
let seccomp_filter =
|
||||
get_seccomp_filter(seccomp_action, Thread::MigrateSendPostcopy, None)
|
||||
.context("creating postcopy serve seccomp filter")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
let handle = thread::Builder::new()
|
||||
.name("migrate-send-postcopy".to_owned())
|
||||
.spawn(move || Self::serve_postcopy(seccomp_filter, fault_stream, guest_memory))
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("spawning postcopy serve thread: {e}"))
|
||||
})?;
|
||||
.context("spawning postcopy serve thread")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
Some(handle)
|
||||
} else {
|
||||
None
|
||||
@@ -1771,9 +1774,9 @@ impl Vmm {
|
||||
// seccomp is disabled (SeccompAction::Allow), in which case there is
|
||||
// nothing to apply.
|
||||
if !seccomp_filter.is_empty() {
|
||||
apply_filter(&seccomp_filter).map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("applying postcopy serve seccomp filter: {e}"))
|
||||
})?;
|
||||
apply_filter(&seccomp_filter)
|
||||
.context("applying postcopy serve seccomp filter")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
}
|
||||
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
@@ -1873,15 +1876,12 @@ impl Vmm {
|
||||
profile: vm_config.cpus.profile,
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {e:?}"))
|
||||
})?
|
||||
.context("Error generating common cpuid")
|
||||
.map_err(MigratableError::MigrateReceive)?
|
||||
};
|
||||
arch::CpuidFeatureEntry::check_cpuid_compatibility(src_vm_cpuid, dest_cpuid).map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error checking cpu feature compatibility': {e:?}"
|
||||
))
|
||||
})
|
||||
arch::CpuidFeatureEntry::check_cpuid_compatibility(src_vm_cpuid, dest_cpuid)
|
||||
.context("Error checking cpu feature compatibility")
|
||||
.map_err(MigratableError::MigrateReceive)
|
||||
}
|
||||
|
||||
fn vm_restore(
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::{cmp, ffi, panic, result, thread, time};
|
||||
|
||||
use acpi_tables::{Aml, aml};
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{Context, anyhow};
|
||||
use arch::{RegionType, layout};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use devices::ioapic;
|
||||
@@ -3196,7 +3196,8 @@ impl Transportable for MemoryManager {
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&memory_file_path)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.with_context(|| format!("Error creating memory snapshot file {memory_file_path:?}"))
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
let total_len: u64 = self
|
||||
.snapshot_memory_ranges
|
||||
@@ -3237,7 +3238,8 @@ impl Transportable for MemoryManager {
|
||||
file_cursor,
|
||||
range.length,
|
||||
)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error writing sparse memory snapshot region")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
}
|
||||
|
||||
if !wrote_sparse {
|
||||
@@ -3247,7 +3249,8 @@ impl Transportable for MemoryManager {
|
||||
// volatile copy.
|
||||
memory_file
|
||||
.seek(SeekFrom::Start(file_cursor))
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error seeking memory snapshot file")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
let mut offset: u64 = 0;
|
||||
// Manual partial-write loop preserves the workaround for
|
||||
// https://github.com/rust-vmm/vm-memory/issues/174
|
||||
@@ -3258,7 +3261,8 @@ impl Transportable for MemoryManager {
|
||||
&mut memory_file,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error writing dense memory snapshot region")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
offset += bytes_written as u64;
|
||||
if offset == range.length {
|
||||
break;
|
||||
@@ -3280,9 +3284,10 @@ impl Migratable for MemoryManager {
|
||||
// Just before we do a bulk copy we want to start/clear the dirty log so that
|
||||
// pages touched during our bulk copy are tracked.
|
||||
fn start_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vm.start_dirty_log().map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error starting VM dirty log {e}"))
|
||||
})?;
|
||||
self.vm
|
||||
.start_dirty_log()
|
||||
.context("Error starting VM dirty log")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
for r in self.guest_memory.memory().iter() {
|
||||
(**r).bitmap().reset();
|
||||
@@ -3292,9 +3297,10 @@ impl Migratable for MemoryManager {
|
||||
}
|
||||
|
||||
fn stop_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vm.stop_dirty_log().map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error stopping VM dirty log {e}"))
|
||||
})?;
|
||||
self.vm
|
||||
.stop_dirty_log()
|
||||
.context("Error stopping VM dirty log")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3304,9 +3310,11 @@ impl Migratable for MemoryManager {
|
||||
fn dirty_log(&mut self) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
for r in &self.guest_ram_mappings {
|
||||
let vm_dirty_bitmap = self.vm.get_dirty_log(r.slot, r.gpa, r.size).map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error getting VM dirty log {e}"))
|
||||
})?;
|
||||
let vm_dirty_bitmap = self
|
||||
.vm
|
||||
.get_dirty_log(r.slot, r.gpa, r.size)
|
||||
.context("Error getting VM dirty log")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
let vmm_dirty_bitmap = match self.guest_memory.memory().find_region(GuestAddress(r.gpa))
|
||||
{
|
||||
Some(region) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{Context, anyhow};
|
||||
use vm_migration::{MigratableError, Snapshot};
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
@@ -56,14 +56,18 @@ pub fn recv_vm_config(source_url: &str) -> result::Result<VmConfig, MigratableEr
|
||||
vm_config_path.push(SNAPSHOT_CONFIG_FILE);
|
||||
|
||||
// Try opening the snapshot file
|
||||
let mut vm_config_file =
|
||||
File::open(vm_config_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?;
|
||||
let mut vm_config_file = File::open(&vm_config_path)
|
||||
.with_context(|| format!("Error opening VM config snapshot file {vm_config_path:?}"))
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
let mut bytes = Vec::new();
|
||||
vm_config_file
|
||||
.read_to_end(&mut bytes)
|
||||
.map_err(|e| MigratableError::MigrateReceive(e.into()))?;
|
||||
.with_context(|| format!("Error reading VM config snapshot file {vm_config_path:?}"))
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
|
||||
serde_json::from_slice(&bytes)
|
||||
.context("Error deserialising VM config snapshot")
|
||||
.map_err(MigratableError::MigrateReceive)
|
||||
}
|
||||
|
||||
pub fn recv_vm_state(source_url: &str) -> result::Result<Snapshot, MigratableError> {
|
||||
@@ -72,14 +76,18 @@ pub fn recv_vm_state(source_url: &str) -> result::Result<Snapshot, MigratableErr
|
||||
vm_state_path.push(SNAPSHOT_STATE_FILE);
|
||||
|
||||
// Try opening the snapshot file
|
||||
let mut vm_state_file =
|
||||
File::open(vm_state_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?;
|
||||
let mut vm_state_file = File::open(&vm_state_path)
|
||||
.with_context(|| format!("Error opening VM state snapshot file {vm_state_path:?}"))
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
let mut bytes = Vec::new();
|
||||
vm_state_file
|
||||
.read_to_end(&mut bytes)
|
||||
.map_err(|e| MigratableError::MigrateReceive(e.into()))?;
|
||||
.with_context(|| format!("Error reading VM state snapshot file {vm_state_path:?}"))
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
|
||||
serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
|
||||
serde_json::from_slice(&bytes)
|
||||
.context("Error deserialising VM state snapshot")
|
||||
.map_err(MigratableError::MigrateReceive)
|
||||
}
|
||||
|
||||
pub fn get_vm_snapshot(snapshot: &Snapshot) -> result::Result<VmSnapshot, MigratableError> {
|
||||
|
||||
@@ -928,9 +928,9 @@ pub(crate) fn send_migration_socket(
|
||||
if let Some(address) = destination_url.strip_prefix("tcp:") {
|
||||
info!("Connecting to TCP socket at {address}");
|
||||
|
||||
let socket = TcpStream::connect(address).map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error connecting to TCP socket: {e}"))
|
||||
})?;
|
||||
let socket = TcpStream::connect(address)
|
||||
.context("Error connecting to TCP socket")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
if let Some(tls_dir) = tls_dir {
|
||||
// The address should have been validated by the API using this exact function.
|
||||
@@ -949,9 +949,9 @@ pub(crate) fn send_migration_socket(
|
||||
let path = socket_url_to_path(destination_url).map_err(MigratableError::MigrateSend)?;
|
||||
info!("Connecting to UNIX socket at {path:?}");
|
||||
|
||||
let socket = UnixStream::connect(&path).map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {e}"))
|
||||
})?;
|
||||
let socket = UnixStream::connect(&path)
|
||||
.context("Error connecting to UNIX socket")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
Ok(SocketStream::Unix(socket))
|
||||
}
|
||||
@@ -1091,11 +1091,8 @@ pub(crate) fn send_memory_ranges(
|
||||
socket,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!(
|
||||
"Error transferring memory to socket: {e}"
|
||||
))
|
||||
})?;
|
||||
.context("Error transferring memory to socket")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
offset += bytes_written as u64;
|
||||
|
||||
if offset == range.length {
|
||||
@@ -1136,11 +1133,8 @@ pub(crate) fn receive_memory_ranges(
|
||||
socket,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error receiving memory from socket: {e}"
|
||||
))
|
||||
})?;
|
||||
.context("Error receiving memory from socket")
|
||||
.map_err(MigratableError::MigrateReceive)?;
|
||||
offset += bytes_read as u64;
|
||||
|
||||
if offset == range.length {
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use std::{any, cmp, result, str, thread};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{Context, anyhow};
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
use arch::PciSpaceInfo;
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
@@ -3019,14 +3019,12 @@ impl Vm {
|
||||
{
|
||||
Request::memory_fd(size_of_val(&slot) as u64)
|
||||
.write_to(socket)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error sending memory fd request: {e}"))
|
||||
})?;
|
||||
.context("Error sending memory fd request")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
socket
|
||||
.send_with_fd(&slot.to_le_bytes()[..], fd)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error sending memory fd: {e}"))
|
||||
})?;
|
||||
.context("Error sending memory fd")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
Response::read_from(socket)?.ok_or_abandon(
|
||||
socket,
|
||||
@@ -3358,9 +3356,8 @@ impl Snapshottable for Vm {
|
||||
profile,
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {e:?}"))
|
||||
})?
|
||||
.context("Error generating common cpuid")
|
||||
.map_err(MigratableError::MigrateReceive)?
|
||||
};
|
||||
|
||||
let vm_snapshot_state = VmSnapshot {
|
||||
@@ -3407,15 +3404,18 @@ impl Transportable for Vm {
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(snapshot_config_path)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error creating VM config snapshot file")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
// Serialize and write the snapshot config
|
||||
let vm_config = serde_json::to_string(self.config.lock().unwrap().deref())
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error serializing VM config snapshot")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
snapshot_config_file
|
||||
.write(vm_config.as_bytes())
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error writing VM config snapshot")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
let mut snapshot_state_path = url_to_path(destination_url)?;
|
||||
snapshot_state_path.push(SNAPSHOT_STATE_FILE);
|
||||
@@ -3426,15 +3426,18 @@ impl Transportable for Vm {
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(snapshot_state_path)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error creating VM state snapshot file")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
// Serialize and write the snapshot state
|
||||
let vm_state =
|
||||
serde_json::to_vec(snapshot).map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
let vm_state = serde_json::to_vec(snapshot)
|
||||
.context("Error serializing VM state snapshot")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
snapshot_state_file
|
||||
.write(&vm_state)
|
||||
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
|
||||
.context("Error writing VM state snapshot")
|
||||
.map_err(MigratableError::MigrateSend)?;
|
||||
|
||||
// Tell the memory manager to also send/write its own snapshot.
|
||||
if let Some(memory_manager_snapshot) = snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID) {
|
||||
|
||||
Reference in New Issue
Block a user