vm-migration: Snapshot should have a unique SnapshotDataSection

There's no reason to carry a HashMap of SnapshotDataSection per
Snapshot. And given we now provide at most one SnapshotDataSection per
Snapshot, there's no need to keep the id part of the SnapshotDataSection
structure.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2022-12-02 14:37:49 +01:00
parent 0489b6314e
commit 5b3bcfa233
8 changed files with 36 additions and 63 deletions

View File

@ -465,7 +465,7 @@ impl VfioCommon {
let state: Option<VfioCommonState> = snapshot let state: Option<VfioCommonState> = snapshot
.as_ref() .as_ref()
.map(|s| s.to_versioned_state(VFIO_COMMON_ID)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(|e| { .map_err(|e| {
VfioPciError::RetrieveVfioCommonState(anyhow!( VfioPciError::RetrieveVfioCommonState(anyhow!(

View File

@ -522,7 +522,7 @@ impl VirtioPciDevice {
let state: Option<VirtioPciDeviceState> = snapshot let state: Option<VirtioPciDeviceState> = snapshot
.as_ref() .as_ref()
.map(|s| s.to_versioned_state(&id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(|e| { .map_err(|e| {
VirtioPciDeviceError::CreateVirtioPciDevice(anyhow!( VirtioPciDeviceError::CreateVirtioPciDevice(anyhow!(

View File

@ -81,9 +81,6 @@ pub trait Pausable {
/// allows for easier and forward compatible extensions. /// allows for easier and forward compatible extensions.
#[derive(Clone, Default, Deserialize, Serialize)] #[derive(Clone, Default, Deserialize, Serialize)]
pub struct SnapshotDataSection { pub struct SnapshotDataSection {
/// The section id.
pub id: String,
/// The section serialized snapshot. /// The section serialized snapshot.
pub snapshot: Vec<u8>, pub snapshot: Vec<u8>,
} }
@ -94,9 +91,8 @@ impl SnapshotDataSection {
where where
T: Deserialize<'a>, T: Deserialize<'a>,
{ {
serde_json::from_slice(&self.snapshot).map_err(|e| { serde_json::from_slice(&self.snapshot)
MigratableError::Restore(anyhow!("Error deserialising: {} {}", self.id, e)) .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
})
} }
/// Generate versioned state /// Generate versioned state
@ -109,39 +105,33 @@ impl SnapshotDataSection {
&T::version_map(), &T::version_map(),
VMM_VERSION, VMM_VERSION,
) )
.map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {} {}", self.id, e))) .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
} }
/// Create from state that can be serialized /// Create from state that can be serialized
pub fn new_from_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
where where
T: Serialize, T: Serialize,
{ {
let snapshot = serde_json::to_vec(state) let snapshot = serde_json::to_vec(state)
.map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {} {}", id, e)))?; .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
let snapshot_data = SnapshotDataSection { let snapshot_data = SnapshotDataSection { snapshot };
id: format!("{}-section", id),
snapshot,
};
Ok(snapshot_data) Ok(snapshot_data)
} }
/// Create from versioned state /// Create from versioned state
pub fn new_from_versioned_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> pub fn new_from_versioned_state<T>(state: &T) -> Result<Self, MigratableError>
where where
T: Versionize + VersionMapped, T: Versionize + VersionMapped,
{ {
let mut snapshot = Vec::new(); let mut snapshot = Vec::new();
state state
.serialize(&mut snapshot, &T::version_map(), VMM_VERSION) .serialize(&mut snapshot, &T::version_map(), VMM_VERSION)
.map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {} {}", id, e)))?; .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
let snapshot_data = SnapshotDataSection { let snapshot_data = SnapshotDataSection { snapshot };
id: format!("{}-section", id),
snapshot,
};
Ok(snapshot_data) Ok(snapshot_data)
} }
@ -168,7 +158,7 @@ pub struct Snapshot {
/// The Snapshottable component's snapshot data. /// The Snapshottable component's snapshot data.
/// A map of snapshot sections, indexed by the section ids. /// A map of snapshot sections, indexed by the section ids.
pub snapshot_data: std::collections::HashMap<String, SnapshotDataSection>, pub snapshot_data: Option<SnapshotDataSection>,
} }
impl Snapshot { impl Snapshot {
@ -186,7 +176,7 @@ impl Snapshot {
T: Serialize, T: Serialize,
{ {
let mut snapshot_data = Snapshot::new(id); let mut snapshot_data = Snapshot::new(id);
snapshot_data.add_data_section(SnapshotDataSection::new_from_state(id, state)?); snapshot_data.add_data_section(SnapshotDataSection::new_from_state(state)?);
Ok(snapshot_data) Ok(snapshot_data)
} }
@ -197,7 +187,7 @@ impl Snapshot {
T: Versionize + VersionMapped, T: Versionize + VersionMapped,
{ {
let mut snapshot_data = Snapshot::new(id); let mut snapshot_data = Snapshot::new(id);
snapshot_data.add_data_section(SnapshotDataSection::new_from_versioned_state(id, state)?); snapshot_data.add_data_section(SnapshotDataSection::new_from_versioned_state(state)?);
Ok(snapshot_data) Ok(snapshot_data)
} }
@ -210,28 +200,28 @@ impl Snapshot {
/// Add a SnapshotDatasection to the component snapshot data. /// Add a SnapshotDatasection to the component snapshot data.
pub fn add_data_section(&mut self, section: SnapshotDataSection) { pub fn add_data_section(&mut self, section: SnapshotDataSection) {
self.snapshot_data.insert(section.id.clone(), section); self.snapshot_data = Some(section);
} }
/// Generate the state data from the snapshot /// Generate the state data from the snapshot
pub fn to_state<'a, T>(&'a self, id: &str) -> Result<T, MigratableError> pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
where where
T: Deserialize<'a>, T: Deserialize<'a>,
{ {
self.snapshot_data self.snapshot_data
.get(&format!("{}-section", id)) .as_ref()
.ok_or_else(|| MigratableError::Restore(anyhow!("Missing section for {}", id)))? .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
.to_state() .to_state()
} }
/// Generate versioned state /// Generate versioned state
pub fn to_versioned_state<T>(&self, id: &str) -> Result<T, MigratableError> pub fn to_versioned_state<T>(&self) -> Result<T, MigratableError>
where where
T: Versionize + VersionMapped, T: Versionize + VersionMapped,
{ {
self.snapshot_data self.snapshot_data
.get(&format!("{}-section", id)) .as_ref()
.ok_or_else(|| MigratableError::Restore(anyhow!("Missing section for {}", id)))? .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
.to_versioned_state() .to_versioned_state()
} }
} }
@ -249,7 +239,7 @@ where
{ {
snapshot snapshot
.and_then(|s| s.snapshots.get(id).map(|s| *s.clone())) .and_then(|s| s.snapshots.get(id).map(|s| *s.clone()))
.map(|s| s.to_versioned_state(id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
} }

View File

@ -403,10 +403,7 @@ impl Snapshottable for Vcpu {
// TODO: The special format of the CPU id can be removed once ready to // TODO: The special format of the CPU id can be removed once ready to
// break live upgrade. // break live upgrade.
let mut vcpu_snapshot = Snapshot::new(&format!("{:03}", self.id)); let mut vcpu_snapshot = Snapshot::new(&format!("{:03}", self.id));
vcpu_snapshot.add_data_section(SnapshotDataSection::new_from_state( vcpu_snapshot.add_data_section(SnapshotDataSection::new_from_state(&saved_state)?);
VCPU_SNAPSHOT_ID,
&saved_state,
)?);
self.saved_state = Some(saved_state); self.saved_state = Some(saved_state);
@ -717,7 +714,7 @@ impl CpuManager {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
vcpu.init(&self.vm)?; vcpu.init(&self.vm)?;
let state: CpuState = snapshot.to_state(VCPU_SNAPSHOT_ID).map_err(|e| { let state: CpuState = snapshot.to_state().map_err(|e| {
Error::VcpuCreate(anyhow!("Could not get vCPU state from snapshot {:?}", e)) Error::VcpuCreate(anyhow!("Could not get vCPU state from snapshot {:?}", e))
})?; })?;
vcpu.vcpu vcpu.vcpu

View File

@ -966,7 +966,7 @@ impl DeviceManager {
trace_scoped!("DeviceManager::new"); trace_scoped!("DeviceManager::new");
let (device_tree, device_id_cnt) = if let Some(snapshot) = snapshot.as_ref() { let (device_tree, device_id_cnt) = if let Some(snapshot) = snapshot.as_ref() {
let state: DeviceManagerState = snapshot.to_state(DEVICE_MANAGER_SNAPSHOT_ID).unwrap(); let state: DeviceManagerState = snapshot.to_state().unwrap();
( (
Arc::new(Mutex::new(state.device_tree.clone())), Arc::new(Mutex::new(state.device_tree.clone())),
state.device_id_cnt, state.device_id_cnt,
@ -1389,7 +1389,7 @@ impl DeviceManager {
} }
let vgic_state = vgic_snapshot let vgic_state = vgic_snapshot
.to_state(&id) .to_state()
.map_err(DeviceManagerError::RestoreGetState)?; .map_err(DeviceManagerError::RestoreGetState)?;
let saved_vcpu_states = self.cpu_manager.lock().unwrap().get_saved_states(); let saved_vcpu_states = self.cpu_manager.lock().unwrap().get_saved_states();
interrupt_controller interrupt_controller
@ -2150,7 +2150,7 @@ impl DeviceManager {
.map_err(DeviceManagerError::EventFd)?, .map_err(DeviceManagerError::EventFd)?,
self.force_iommu, self.force_iommu,
snapshot snapshot
.map(|s| s.to_versioned_state(&id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(DeviceManagerError::RestoreGetState)?, .map_err(DeviceManagerError::RestoreGetState)?,
) { ) {
@ -2249,7 +2249,7 @@ impl DeviceManager {
.try_clone() .try_clone()
.map_err(DeviceManagerError::EventFd)?, .map_err(DeviceManagerError::EventFd)?,
snapshot snapshot
.map(|s| s.to_versioned_state(&id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(DeviceManagerError::RestoreGetState)?, .map_err(DeviceManagerError::RestoreGetState)?,
) )
@ -2332,7 +2332,7 @@ impl DeviceManager {
.map_err(DeviceManagerError::EventFd)?, .map_err(DeviceManagerError::EventFd)?,
self.force_iommu, self.force_iommu,
snapshot snapshot
.map(|s| s.to_versioned_state(&id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(DeviceManagerError::RestoreGetState)?, .map_err(DeviceManagerError::RestoreGetState)?,
) { ) {
@ -2349,7 +2349,7 @@ impl DeviceManager {
) )
} else { } else {
let state = snapshot let state = snapshot
.map(|s| s.to_versioned_state(&id)) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(DeviceManagerError::RestoreGetState)?; .map_err(DeviceManagerError::RestoreGetState)?;
@ -4456,10 +4456,7 @@ impl Snapshottable for DeviceManager {
} }
// Then we store the DeviceManager state. // Then we store the DeviceManager state.
snapshot.add_data_section(SnapshotDataSection::new_from_state( snapshot.add_data_section(SnapshotDataSection::new_from_state(&self.state())?);
DEVICE_MANAGER_SNAPSHOT_ID,
&self.state(),
)?);
Ok(snapshot) Ok(snapshot)
} }

View File

@ -1160,9 +1160,8 @@ impl MemoryManager {
let mut memory_file_path = url_to_path(source_url).map_err(Error::Restore)?; let mut memory_file_path = url_to_path(source_url).map_err(Error::Restore)?;
memory_file_path.push(String::from(SNAPSHOT_FILENAME)); memory_file_path.push(String::from(SNAPSHOT_FILENAME));
let mem_snapshot: MemoryManagerSnapshotData = snapshot let mem_snapshot: MemoryManagerSnapshotData =
.to_versioned_state(MEMORY_MANAGER_SNAPSHOT_ID) snapshot.to_versioned_state().map_err(Error::Restore)?;
.map_err(Error::Restore)?;
let mm = MemoryManager::new( let mm = MemoryManager::new(
vm, vm,
@ -2444,7 +2443,6 @@ impl Snapshottable for MemoryManager {
self.snapshot_memory_ranges = memory_ranges; self.snapshot_memory_ranges = memory_ranges;
memory_manager_snapshot.add_data_section(SnapshotDataSection::new_from_versioned_state( memory_manager_snapshot.add_data_section(SnapshotDataSection::new_from_versioned_state(
MEMORY_MANAGER_SNAPSHOT_ID,
&self.snapshot_data(), &self.snapshot_data(),
)?); )?);

View File

@ -4,10 +4,7 @@
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use crate::coredump::GuestDebuggableError; use crate::coredump::GuestDebuggableError;
use crate::{ use crate::{config::VmConfig, vm::VmSnapshot};
config::VmConfig,
vm::{VmSnapshot, VM_SNAPSHOT_ID},
};
use anyhow::anyhow; use anyhow::anyhow;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
@ -71,13 +68,8 @@ pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, Migratab
} }
pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> { pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> {
if let Some(vm_section) = snapshot if let Some(snapshot_data) = snapshot.snapshot_data.as_ref() {
.snapshot_data return snapshot_data.to_state();
.get(&format!("{}-section", VM_SNAPSHOT_ID))
{
return serde_json::from_slice(&vm_section.snapshot).map_err(|e| {
MigratableError::Restore(anyhow!("Could not deserialize VM snapshot {}", e))
});
} }
Err(MigratableError::Restore(anyhow!( Err(MigratableError::Restore(anyhow!(

View File

@ -2522,7 +2522,6 @@ impl Snapshottable for Vm {
vm_snapshot.add_snapshot(self.device_manager.lock().unwrap().snapshot()?); vm_snapshot.add_snapshot(self.device_manager.lock().unwrap().snapshot()?);
vm_snapshot.add_data_section(SnapshotDataSection { vm_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", VM_SNAPSHOT_ID),
snapshot: vm_snapshot_data, snapshot: vm_snapshot_data,
}); });