Skip to content

Commit aa14c57

Browse files
committed
feat: allow loading older snapshots
Now that we have logic for translating snapshot formats, we can allow the /snapshot/load API to parse v1.10 and v1.12 snapshots. We change the logic that parses the snapshot file to first read the version from the file and then (if needed) translate it to the expected v1.14 version. Currently older versions supported are v1.10 and v1.12. Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
1 parent 01c9a38 commit aa14c57

2 files changed

Lines changed: 35 additions & 13 deletions

File tree

src/vmm/src/persist/mod.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::os::unix::io::AsRawFd;
1111
use std::os::unix::net::UnixStream;
1212
use std::path::Path;
1313
use std::sync::{Arc, Mutex};
14+
use std::time::Instant;
1415

1516
use semver::Version;
1617
use serde::{Deserialize, Serialize};
@@ -29,7 +30,7 @@ use crate::device_manager::{DevicePersistError, DevicesState};
2930
use crate::logger::{info, warn};
3031
use crate::resources::VmResources;
3132
use crate::seccomp::BpfThreadMap;
32-
use crate::snapshot::Snapshot;
33+
use crate::snapshot::{Snapshot, SnapshotError, SnapshotHdr};
3334
use crate::utils::u64_to_usize;
3435
use crate::vmm_config::boot_source::BootSourceConfig;
3536
use crate::vmm_config::instance_info::InstanceInfo;
@@ -451,10 +452,36 @@ pub enum SnapshotStateFromFileError {
451452
fn snapshot_state_from_file(
452453
snapshot_path: &Path,
453454
) -> Result<MicrovmState, SnapshotStateFromFileError> {
454-
let mut snapshot_reader = File::open(snapshot_path)?;
455-
let snapshot = Snapshot::load(&mut snapshot_reader)?;
455+
let start = Instant::now();
456456

457-
Ok(snapshot.data)
457+
let data = std::fs::read(snapshot_path)?;
458+
let version = SnapshotHdr::load(&mut data.as_slice())?.version;
459+
460+
let mut snapshot_reader = data.as_slice();
461+
let data = match (version.major, version.minor) {
462+
(8, 0) => Snapshot::load(&mut snapshot_reader)?.data,
463+
(6, 0) => {
464+
let v12_state = Snapshot::<v1_12::MicrovmState>::load(&mut snapshot_reader)?;
465+
MicrovmState::try_from(v12_state.data).unwrap()
466+
}
467+
(4, 0) => {
468+
let v10_state = Snapshot::<v1_10::MicrovmState>::load(&mut snapshot_reader)?;
469+
let v12_state = v1_12::MicrovmState::from(v10_state.data);
470+
MicrovmState::try_from(v12_state).unwrap()
471+
}
472+
_ => {
473+
return Err(SnapshotStateFromFileError::Load(
474+
SnapshotError::InvalidFormatVersion(version),
475+
));
476+
}
477+
};
478+
479+
info!(
480+
"Loading snapshot file took {} usec",
481+
start.elapsed().as_micros()
482+
);
483+
484+
Ok(data)
458485
}
459486

460487
/// Error type for [`guest_memory_from_file`].

src/vmm/src/snapshot/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,26 +81,21 @@ fn serialize<S: Serialize, W: Write>(data: &S, write: &mut W) -> Result<(), Snap
8181

8282
/// Firecracker snapshot header
8383
#[derive(Debug, Serialize, Deserialize)]
84-
struct SnapshotHdr {
84+
pub struct SnapshotHdr {
8585
/// magic value
86-
magic: u64,
86+
pub magic: u64,
8787
/// Snapshot data version
88-
version: Version,
88+
pub version: Version,
8989
}
9090

9191
impl SnapshotHdr {
92-
fn load(buf: &mut &[u8]) -> Result<Self, SnapshotError> {
92+
pub(crate) fn load(buf: &mut &[u8]) -> Result<Self, SnapshotError> {
9393
let (hdr, bytes_read) = bincode::serde::decode_from_slice::<Self, _>(buf, BINCODE_CONFIG)?;
9494

9595
if hdr.magic != SNAPSHOT_MAGIC_ID {
9696
return Err(SnapshotError::InvalidMagic(hdr.magic));
9797
}
9898

99-
if hdr.version.major != SNAPSHOT_VERSION.major || hdr.version.minor > SNAPSHOT_VERSION.minor
100-
{
101-
return Err(SnapshotError::InvalidFormatVersion(hdr.version));
102-
}
103-
10499
*buf = &buf[bytes_read..];
105100

106101
Ok(hdr)

0 commit comments

Comments
 (0)