misc: Simplify snapshot/restore by using helper functions

Simplify snapshot & restore code by using generics to specify helper
functions that take / make a Serialize / Deserialize struct

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-04-08 10:20:10 +01:00
parent 4e4c5fb6aa
commit 6f5d4702d4
18 changed files with 108 additions and 550 deletions

View File

@ -15,8 +15,7 @@ pub mod kvm {
use std::sync::Arc; use std::sync::Arc;
use std::{boxed::Box, result}; use std::{boxed::Box, result};
use vm_migration::{ use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable, Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
Transportable,
}; };
/// Errors thrown while saving/restoring the GICv3. /// Errors thrown while saving/restoring the GICv3.
@ -230,42 +229,15 @@ pub mod kvm {
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let gicr_typers = self.gicr_typers.clone(); let gicr_typers = self.gicr_typers.clone();
let snapshot = serde_json::to_vec(&self.state(&gicr_typers).unwrap()) Snapshot::new_from_state(&self.id(), &self.state(&gicr_typers).unwrap())
.map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut gic_v3_snapshot = Snapshot::new(self.id().as_str());
gic_v3_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id()),
snapshot,
});
Ok(gic_v3_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(gic_v3_section) = snapshot
.snapshot_data
.get(&format!("{}-section", self.id()))
{
let gic_v3_state = match serde_json::from_slice(&gic_v3_section.snapshot) {
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize GICv3 {}",
error
)))
}
};
let gicr_typers = self.gicr_typers.clone(); let gicr_typers = self.gicr_typers.clone();
return self.set_state(&gicr_typers, &gic_v3_state).map_err(|e| { self.set_state(&gicr_typers, &snapshot.to_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e)) MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
}); })
}
Err(MigratableError::Restore(anyhow!(
"Could not find GICv3 snapshot section"
)))
} }
} }

View File

@ -20,10 +20,7 @@ use vm_device::interrupt::{
}; };
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -418,38 +415,13 @@ impl Snapshottable for Ioapic {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut ioapic_snapshot = Snapshot::new(self.id.as_str());
ioapic_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(ioapic_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(ioapic_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?).map_err(|e| {
let ioapic_state = match serde_json::from_slice(&ioapic_section.snapshot) { MigratableError::Restore(anyhow!("Could not restore state for {}: {:?}", self.id, e))
Ok(state) => state, })
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize IOAPIC {}",
error
)))
}
};
return self.set_state(&ioapic_state).map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore IOAPIC state {:?}", e))
});
}
Err(MigratableError::Restore(anyhow!(
"Could not find IOAPIC snapshot section"
)))
} }
} }

View File

@ -8,16 +8,12 @@
//! //!
use crate::{read_le_u32, write_le_u32}; use crate::{read_le_u32, write_le_u32};
use anyhow::anyhow;
use std::result; use std::result;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::{fmt, io}; use std::{fmt, io};
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
const OFS_DATA: u64 = 0x400; // Data Register const OFS_DATA: u64 = 0x400; // Data Register
const GPIODIR: u64 = 0x400; // Direction Register const GPIODIR: u64 = 0x400; // Direction Register
@ -317,38 +313,12 @@ impl Snapshottable for Gpio {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut gpio_snapshot = Snapshot::new(self.id.as_str());
gpio_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(gpio_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(gpio_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let gpio_state = match serde_json::from_slice(&gpio_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize GPIO {}",
error
)))
}
};
self.set_state(&gpio_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find the GPIO snapshot section"
)))
} }
} }

View File

@ -5,16 +5,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use anyhow::anyhow;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::{io, result}; use std::{io, result};
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::errno::Result; use vmm_sys_util::errno::Result;
const LOOP_SIZE: usize = 0x40; const LOOP_SIZE: usize = 0x40;
@ -292,38 +288,12 @@ impl Snapshottable for Serial {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut serial_snapshot = Snapshot::new(self.id.as_str());
serial_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(serial_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(serial_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let serial_state = match serde_json::from_slice(&serial_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize SERIAL {}",
error
)))
}
};
self.set_state(&serial_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find the serial snapshot section"
)))
} }
} }

View File

@ -7,17 +7,13 @@
//! //!
use crate::{read_le_u32, write_le_u32}; use crate::{read_le_u32, write_le_u32};
use anyhow::anyhow;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::{io, result}; use std::{io, result};
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
/* Registers */ /* Registers */
const UARTDR: u64 = 0; const UARTDR: u64 = 0;
@ -361,38 +357,12 @@ impl Snapshottable for Pl011 {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut pl011_snapshot = Snapshot::new(self.id.as_str());
pl011_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(pl011_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(pl011_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let pl011_state = match serde_json::from_slice(&pl011_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize PL011 {}",
error
)))
}
};
self.set_state(&pl011_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find the PL011 snapshot section"
)))
} }
} }

View File

@ -4,11 +4,10 @@
use crate::device::BarReprogrammingParams; use crate::device::BarReprogrammingParams;
use crate::{MsixConfig, PciInterruptPin}; use crate::{MsixConfig, PciInterruptPin};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_migration::{MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
// The number of 32bit registers in the config space, 4096 bytes. // The number of 32bit registers in the config space, 4096 bytes.
const NUM_CONFIGURATION_REGISTERS: usize = 1024; const NUM_CONFIGURATION_REGISTERS: usize = 1024;
@ -890,43 +889,12 @@ impl Snapshottable for PciConfiguration {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id(), &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut config_snapshot = Snapshot::new(self.id().as_str());
config_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id()),
snapshot,
});
Ok(config_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(config_section) = snapshot self.set_state(&snapshot.to_state(&self.id())?);
.snapshot_data Ok(())
.get(&format!("{}-section", self.id()))
{
let config_state = match serde_json::from_slice(&config_section.snapshot) {
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize {}: {}",
self.id(),
error
)))
}
};
self.set_state(&config_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find {} snapshot section",
self.id()
)))
} }
} }

View File

@ -16,7 +16,7 @@ use vm_device::interrupt::{
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig, InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
}; };
use vm_memory::ByteValued; use vm_memory::ByteValued;
use vm_migration::{MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048; const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
const MSIX_TABLE_ENTRIES_MODULO: u64 = 16; const MSIX_TABLE_ENTRIES_MODULO: u64 = 16;
@ -432,41 +432,18 @@ impl Snapshottable for MsixConfig {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id(), &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut msix_snapshot = Snapshot::new(self.id().as_str());
msix_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id()),
snapshot,
});
Ok(msix_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(msix_section) = snapshot self.set_state(&snapshot.to_state(&self.id())?)
.snapshot_data .map_err(|e| {
.get(&format!("{}-section", self.id())) MigratableError::Restore(anyhow!(
{ "Could not restore state for {}: {:?}",
let msix_state = match serde_json::from_slice(&msix_section.snapshot) { self.id(),
Ok(state) => state, e
Err(error) => { ))
return Err(MigratableError::Restore(anyhow!( })
"Could not deserialize MSI-X {}",
error
)))
}
};
return self.set_state(&msix_state).map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore MSI-X state {:?}", e))
});
}
Err(MigratableError::Restore(anyhow!(
"Could not find MSI-X snapshot section"
)))
} }
} }

View File

@ -16,7 +16,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::VirtioInterrupt; use crate::VirtioInterrupt;
use anyhow::anyhow;
use block_util::{ use block_util::{
async_io::AsyncIo, async_io::AsyncIoError, async_io::DiskFile, build_disk_image_id, Request, async_io::AsyncIo, async_io::AsyncIoError, async_io::DiskFile, build_disk_image_id, Request,
RequestType, VirtioBlockConfig, RequestType, VirtioBlockConfig,
@ -34,10 +33,7 @@ use std::thread;
use std::{collections::HashMap, convert::TryInto}; use std::{collections::HashMap, convert::TryInto};
use virtio_bindings::bindings::virtio_blk::*; use virtio_bindings::bindings::virtio_blk::*;
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const SECTOR_SHIFT: u8 = 9; const SECTOR_SHIFT: u8 = 9;
@ -678,37 +674,12 @@ impl Snapshottable for Block {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id(), &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut block_snapshot = Snapshot::new(self.id.as_str());
block_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(block_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(block_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let block_state = match serde_json::from_slice(&block_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize BLOCK {}",
error
)))
}
};
self.set_state(&block_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find BLOCK snapshot section"
)))
} }
} }
impl Transportable for Block {} impl Transportable for Block {}

View File

@ -9,7 +9,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::VirtioInterrupt; use crate::VirtioInterrupt;
use anyhow::anyhow;
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use seccomp::{SeccompAction, SeccompFilter}; use seccomp::{SeccompAction, SeccompFilter};
use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::ser::{Serialize, SerializeStruct, Serializer};
@ -24,10 +23,7 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use std::thread; use std::thread;
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 256; const QUEUE_SIZE: u16 = 256;
@ -512,37 +508,12 @@ impl Snapshottable for Console {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut console_snapshot = Snapshot::new(self.id.as_str());
console_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(console_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(console_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let console_state = match serde_json::from_slice(&console_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize CONSOLE {}",
error
)))
}
};
self.set_state(&console_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find CONSOLE snapshot section"
)))
} }
} }
impl Transportable for Console {} impl Transportable for Console {}

View File

@ -10,7 +10,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::{DmaRemapping, VirtioInterrupt, VirtioInterruptType}; use crate::{DmaRemapping, VirtioInterrupt, VirtioInterruptType};
use anyhow::anyhow;
use seccomp::{SeccompAction, SeccompFilter}; use seccomp::{SeccompAction, SeccompFilter};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
@ -27,10 +26,7 @@ use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
GuestMemoryError, GuestMemoryMmap, GuestMemoryError, GuestMemoryMmap,
}; };
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
/// Queues sizes /// Queues sizes
@ -975,37 +971,12 @@ impl Snapshottable for Iommu {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut iommu_snapshot = Snapshot::new(self.id.as_str());
iommu_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(iommu_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(iommu_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let iommu_state = match serde_json::from_slice(&iommu_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize IOMMU {}",
error
)))
}
};
self.set_state(&iommu_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find IOMMU snapshot section"
)))
} }
} }
impl Transportable for Iommu {} impl Transportable for Iommu {}

View File

@ -17,7 +17,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::VirtioInterrupt; use crate::VirtioInterrupt;
use anyhow::anyhow;
use net_util::{ use net_util::{
open_tap, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio, Tap, TapError, TxVirtio, open_tap, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio, Tap, TapError, TxVirtio,
}; };
@ -34,10 +33,7 @@ use std::{collections::HashMap, convert::TryInto};
use virtio_bindings::bindings::virtio_net::*; use virtio_bindings::bindings::virtio_net::*;
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
// The guest has made a buffer available to receive a frame into. // The guest has made a buffer available to receive a frame into.
@ -685,37 +681,12 @@ impl Snapshottable for Net {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut net_snapshot = Snapshot::new(self.id.as_str());
net_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(net_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(net_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let net_state = match serde_json::from_slice(&net_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize NET {}",
error
)))
}
};
self.set_state(&net_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find NET snapshot section"
)))
} }
} }
impl Transportable for Net {} impl Transportable for Net {}

View File

@ -14,7 +14,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::{VirtioInterrupt, VirtioInterruptType}; use crate::{VirtioInterrupt, VirtioInterruptType};
use anyhow::anyhow;
use seccomp::{SeccompAction, SeccompFilter}; use seccomp::{SeccompAction, SeccompFilter};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::fs::File; use std::fs::File;
@ -29,10 +28,7 @@ use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
GuestMemoryError, GuestMemoryMmap, MmapRegion, GuestMemoryError, GuestMemoryMmap, MmapRegion,
}; };
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 256; const QUEUE_SIZE: u16 = 256;
@ -461,37 +457,12 @@ impl Snapshottable for Pmem {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut pmem_snapshot = Snapshot::new(self.id.as_str());
pmem_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(pmem_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(pmem_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let pmem_state = match serde_json::from_slice(&pmem_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize PMEM {}",
error
)))
}
};
self.set_state(&pmem_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find PMEM snapshot section"
)))
} }
} }

View File

@ -10,7 +10,6 @@ use super::{
}; };
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::{VirtioInterrupt, VirtioInterruptType}; use crate::{VirtioInterrupt, VirtioInterruptType};
use anyhow::anyhow;
use seccomp::{SeccompAction, SeccompFilter}; use seccomp::{SeccompAction, SeccompFilter};
use std::fs::File; use std::fs::File;
use std::io; use std::io;
@ -20,10 +19,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::thread; use std::thread;
use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 256; const QUEUE_SIZE: u16 = 256;
@ -303,37 +299,12 @@ impl Snapshottable for Rng {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut rng_snapshot = Snapshot::new(self.id.as_str());
rng_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(rng_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(rng_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let rng_state = match serde_json::from_slice(&rng_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize RNG {}",
error
)))
}
};
self.set_state(&rng_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find RNG snapshot section"
)))
} }
} }

View File

@ -8,12 +8,11 @@
extern crate byteorder; extern crate byteorder;
use crate::{Queue, VirtioDevice}; use crate::{Queue, VirtioDevice};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
use vm_migration::{MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct VirtioPciCommonConfigState { pub struct VirtioPciCommonConfigState {
@ -291,43 +290,12 @@ impl Snapshottable for VirtioPciCommonConfig {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id(), &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut config_snapshot = Snapshot::new(self.id().as_str());
config_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id()),
snapshot,
});
Ok(config_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(config_section) = snapshot self.set_state(&snapshot.to_state(&self.id())?);
.snapshot_data Ok(())
.get(&format!("{}-section", self.id()))
{
let config_state = match serde_json::from_slice(&config_section.snapshot) {
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize {}: {}",
self.id(),
error
)))
}
};
self.set_state(&config_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find {} snapshot section",
self.id()
)))
} }
} }

View File

@ -41,10 +41,7 @@ use vm_memory::{
Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap,
GuestUsize, Le32, GuestUsize, Le32,
}; };
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vm_virtio::{queue, VirtioIommuRemapping, VIRTIO_MSI_NO_VECTOR}; use vm_virtio::{queue, VirtioIommuRemapping, VIRTIO_MSI_NO_VECTOR};
use vmm_sys_util::{errno::Result, eventfd::EventFd}; use vmm_sys_util::{errno::Result, eventfd::EventFd};
@ -1078,14 +1075,7 @@ impl Snapshottable for VirtioPciDevice {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = let mut virtio_pci_dev_snapshot = Snapshot::new_from_state(&self.id, &self.state())?;
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut virtio_pci_dev_snapshot = Snapshot::new(self.id.as_str());
virtio_pci_dev_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
// Snapshot PciConfiguration // Snapshot PciConfiguration
virtio_pci_dev_snapshot.add_snapshot(self.configuration.snapshot()?); virtio_pci_dev_snapshot.add_snapshot(self.configuration.snapshot()?);

View File

@ -17,7 +17,6 @@ use crate::{
VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST,
VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
}; };
use anyhow::anyhow;
/// This is the `VirtioDevice` implementation for our vsock device. It handles the virtio-level /// This is the `VirtioDevice` implementation for our vsock device. It handles the virtio-level
/// device logic: feature negotiation, device configuration, and device activation. /// device logic: feature negotiation, device configuration, and device activation.
/// The run-time device logic (i.e. event-driven data handling) is implemented by /// The run-time device logic (i.e. event-driven data handling) is implemented by
@ -47,10 +46,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Barrier, RwLock}; use std::sync::{Arc, Barrier, RwLock};
use std::thread; use std::thread;
use vm_memory::{GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 256; const QUEUE_SIZE: u16 = 256;
@ -508,37 +504,12 @@ where
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut vsock_snapshot = Snapshot::new(self.id.as_str());
vsock_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(vsock_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(vsock_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) { self.set_state(&snapshot.to_state(&self.id)?);
let vsock_state = match serde_json::from_slice(&vsock_section.snapshot) { Ok(())
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize VSOCK {}",
error
)))
}
};
self.set_state(&vsock_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find VSOCK snapshot section"
)))
} }
} }
impl<B> Transportable for Vsock<B> where B: VsockBackend + Sync + 'static {} impl<B> Transportable for Vsock<B> where B: VsockBackend + Sync + 'static {}

View File

@ -23,10 +23,7 @@ use std::sync::{Arc, Barrier, Mutex};
use std::thread; use std::thread;
use std::time::Instant; use std::time::Instant;
use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vm_migration::{ use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 8; const QUEUE_SIZE: u16 = 8;
@ -395,38 +392,12 @@ impl Snapshottable for Watchdog {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = Snapshot::new_from_state(&self.id, &self.state())
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut watchdog_snapshot = Snapshot::new(self.id.as_str());
watchdog_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", self.id),
snapshot,
});
Ok(watchdog_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(watchdog_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) self.set_state(&snapshot.to_state(&self.id)?);
{ Ok(())
let watchdog_state = match serde_json::from_slice(&watchdog_section.snapshot) {
Ok(state) => state,
Err(error) => {
return Err(MigratableError::Restore(anyhow!(
"Could not deserialize watchdog {}",
error
)))
}
};
self.set_state(&watchdog_state);
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find watchdog snapshot section"
)))
} }
} }

View File

@ -9,6 +9,8 @@ extern crate thiserror;
extern crate serde_derive; extern crate serde_derive;
extern crate vm_memory; extern crate vm_memory;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
pub mod protocol; pub mod protocol;
@ -97,6 +99,23 @@ impl Snapshot {
} }
} }
/// Create from state that can be serialized
pub fn new_from_state<T>(id: &str, state: &T) -> Result<Self, MigratableError>
where
T: Serialize,
{
let snapshot = serde_json::to_vec(state)
.map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {} {}", id, e)))?;
let mut snapshot_data = Snapshot::new(id);
snapshot_data.add_data_section(SnapshotDataSection {
id: format!("{}-section", id),
snapshot,
});
Ok(snapshot_data)
}
/// Add a sub-component's Snapshot to the Snapshot. /// Add a sub-component's Snapshot to the Snapshot.
pub fn add_snapshot(&mut self, snapshot: Snapshot) { pub fn add_snapshot(&mut self, snapshot: Snapshot) {
self.snapshots self.snapshots
@ -107,6 +126,20 @@ impl Snapshot {
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.insert(section.id.clone(), section);
} }
/// Generate the state data from the snapshot
pub fn to_state<'a, T>(&'a self, id: &str) -> Result<T, MigratableError>
where
T: Deserialize<'a>,
{
let section = self
.snapshot_data
.get(&format!("{}-section", id))
.ok_or_else(|| MigratableError::Restore(anyhow!("Missing section for {}", id)))?;
serde_json::from_slice(&section.snapshot)
.map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {} {}", id, e)))
}
} }
/// A snapshottable component can be snapshotted. /// A snapshottable component can be snapshotted.