Skip to content

Commit 3252af5

Browse files
committed
Snapshot refactoring
Signed-off-by: Gabriel Keller <gabrieljameskeller@gmail.com>
1 parent 0c3606a commit 3252af5

File tree

1 file changed

+87
-66
lines changed

1 file changed

+87
-66
lines changed

src/vmm/src/snapshot/mod.rs

Lines changed: 87 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use std::io::{Read, Write};
3030

3131
use bincode::config;
3232
use bincode::config::{Configuration, Fixint, Limit, LittleEndian};
33+
use bincode::error::{DecodeError, EncodeError};
3334
use semver::Version;
3435
use serde::de::DeserializeOwned;
3536
use serde::{Deserialize, Serialize};
@@ -72,35 +73,37 @@ pub enum SnapshotError {
7273

7374
/// Firecracker snapshot header
7475
#[derive(Debug, Serialize, Deserialize)]
75-
pub struct SnapshotHdr {
76-
/// magic value
76+
struct SnapshotHdr {
77+
/// Magic value
7778
magic: u64,
7879
/// Snapshot data version
7980
version: Version,
8081
}
8182

8283
impl SnapshotHdr {
83-
pub fn new(version: Version) -> Self {
84+
/// Create a new header for writing snapshots
85+
fn new(version: Version) -> Self {
8486
Self {
8587
magic: SNAPSHOT_MAGIC_ID,
8688
version,
8789
}
8890
}
8991

90-
pub fn load<R: Read>(reader: &mut R) -> Result<Self, SnapshotError> {
92+
/// Load and deserialize just the header (magic + version)
93+
fn load<R: Read>(reader: &mut R) -> Result<Self, SnapshotError> {
9194
let hdr: SnapshotHdr = deserialize(reader)?;
92-
93-
Ok(hdr)
95+
if hdr.magic != SNAPSHOT_MAGIC_ID {
96+
Err(SnapshotError::InvalidMagic(hdr.magic))
97+
}
98+
else {
99+
Ok(hdr)
100+
}
94101
}
95102

96-
/// Helper function to deserialize an object from a reader
97-
pub fn deserialize<T, O>(reader: &mut T) -> Result<O, SnapshotError>
98-
where
99-
T: Read,
100-
O: DeserializeOwned + Debug,
101-
{
102-
bincode::serde::decode_from_std_read(reader, BINCODE_CONFIG)
103-
.map_err(|err| SnapshotError::Serde(err.to_string()))
103+
/// Serialize and write just the header
104+
fn store<W: Write>(&self, writer: &mut W) -> Result<(), SnapshotError> {
105+
serialize(writer, self)?;
106+
Ok(())
104107
}
105108
}
106109

@@ -116,51 +119,44 @@ impl SnapshotHdr {
116119
Ok(())
117120
}
118121

119-
impl<Data: DeserializeOwned> Snapshot<Data> {
120-
pub fn load_unchecked<R: Read>(reader: &mut R) -> Result<Self, SnapshotError>
121-
where
122-
Data: DeserializeOwned + Debug,
123-
{
124-
let hdr: SnapshotHdr = deserialize(reader)?;
125-
if hdr.magic != SNAPSHOT_MAGIC_ID {
126-
return Err(SnapshotError::InvalidMagic(hdr.magic));
127-
}
128-
129-
let data: Data = deserialize(reader)?;
122+
// Implementations for deserializing snapshots
123+
// Publicly exposed functions:
124+
// - load_unchecked()
125+
//- load()
126+
impl<Data: DeserializeOwned + Debug> Snapshot<Data> {
127+
/// Load without CRC or version‐check, but verify magic via `SnapshotHdr::load`.
128+
pub fn load_unchecked<R: Read + Debug>(reader: &mut R) -> Result<Self, SnapshotError> {
129+
// this calls `deserialize` + checks magic internally
130+
let hdr: SnapshotHdr = SnapshotHdr::load(reader)?;
131+
let data: Data = deserialize(reader)?;
130132
Ok(Self { header: hdr, data })
131133
}
132134

133-
pub fn load<R: Read>(reader: &mut R, snapshot_len: usize) -> Result<Self, SnapshotError>
134-
where
135-
Data: DeserializeOwned + Debug,
136-
{
135+
/// Load with CRC64 validation in one pass, using `load_unchecked` for header+data.
136+
pub fn load<R: Read + Debug>(reader: &mut R) -> Result<Self, SnapshotError> {
137+
// 1) Wrap in CRC reader
137138
let mut crc_reader = CRC64Reader::new(reader);
138139

139-
// Fail-fast if the snapshot length is too small
140-
let raw_snapshot_len = snapshot_len
141-
.checked_sub(std::mem::size_of::<u64>())
142-
.ok_or(SnapshotError::InvalidSnapshotSize)?;
143-
144-
// Read everything apart from the CRC.
145-
let mut snapshot = vec![0u8; raw_snapshot_len];
146-
crc_reader
147-
.read_exact(&mut snapshot)
148-
.map_err(|ref err| SnapshotError::Io(err.raw_os_error().unwrap_or(libc::EINVAL)))?;
149-
150-
// Since the reader updates the checksum as bytes ar being read from it, the order of these
151-
// 2 statements is important, we first get the checksum computed on the read bytes
152-
// then read the stored checksum.
153-
let computed_checksum = crc_reader.checksum();
154-
let stored_checksum: u64 = deserialize(&mut crc_reader)?;
155-
if computed_checksum != stored_checksum {
156-
return Err(SnapshotError::Crc64(computed_checksum));
140+
// 2) Parse header + payload & magic‐check
141+
let snapshot = Snapshot::load_unchecked(&mut crc_reader)?;
142+
143+
// 3) Grab the computed CRC over everything read so far
144+
let computed = crc_reader.checksum();
145+
146+
// 4) Deserialize the trailing u64 and compare
147+
let stored: u64 = deserialize(&mut crc_reader)?;
148+
if stored != computed {
149+
return Err(SnapshotError::Crc64(computed));
157150
}
158151

159-
let mut snapshot_slice: &[u8] = snapshot.as_mut_slice();
160-
Snapshot::load_unchecked::<_>(&mut snapshot_slice)
152+
Ok(snapshot)
161153
}
162154
}
163155

156+
// Implementations for serializing snapshots
157+
// Publicly-exposed *methods*:
158+
// - save(self,...)
159+
// - save_with_crc(self,...)
164160
impl<Data: Serialize + Debug> Snapshot<Data> {
165161
pub fn save<W: Write>(&self, mut writer: &mut W) -> Result<usize, SnapshotError> {
166162
// Write magic value and snapshot version
@@ -179,8 +175,12 @@ impl<Data: Serialize + Debug> Snapshot<Data> {
179175
}
180176
}
181177

178+
// General methods for snapshots (related to serialization, see above, since an
179+
// instance is needed to serialize)
182180
impl<Data> Snapshot<Data> {
183-
pub fn new(header: SnapshotHdr, data: Data) -> Self {
181+
/// Construct from a pre‐built header + payload
182+
pub fn new(version: Version, data: Data) -> Self {
183+
header = SnapshotHdr::new(version);
184184
Snapshot { header, data }
185185
}
186186

@@ -189,35 +189,56 @@ impl<Data> Snapshot<Data> {
189189
}
190190
}
191191

192-
/// Helper function to deserialize an object from a reader
192+
/// Deserialize any `O: DeserializeOwned + Debug` via bincode + our config,
193193
fn deserialize<T, O>(reader: &mut T) -> Result<O, SnapshotError>
194194
where
195195
T: Read,
196196
O: DeserializeOwned + Debug,
197197
{
198-
// flags below are those used by default by bincode::deserialize_from, plus `with_limit`.
199-
bincode::DefaultOptions::new()
200-
.with_limit(VM_STATE_DESERIALIZE_LIMIT)
201-
.with_fixint_encoding()
202-
.allow_trailing_bytes() // need this because we deserialize header and snapshot from the same file, so after
203-
// reading the header, there will be trailing bytes.
204-
.deserialize_from(reader)
205-
.map_err(|err| SnapshotError::Serde(err.to_string()))
198+
bincode::serde::decode_from_std_read(reader, BINCODE_CONFIG)
199+
.map_err(|err| match err {
200+
// The reader hit an actual IO error.
201+
DecodeError::Io { inner, .. } =>
202+
SnapshotError::Io(inner.raw_os_error().unwrap_or(EIO)),
203+
204+
// Not enough bytes in the input for what we expected.
205+
DecodeError::UnexpectedEnd { .. } |
206+
DecodeError::LimitExceeded =>
207+
SnapshotError::InvalidSnapshotSize,
208+
209+
// Anything else is a ser/de format issue.
210+
other =>
211+
SnapshotError::Serde(other.to_string()),
212+
})
206213
}
207214

208-
/// Helper function to serialize an object to a writer
215+
/// Serialize any `O: Serialize + Debug` into a Vec, write it, and return the byte‐count,
209216
fn serialize<T, O>(writer: &mut T, data: &O) -> Result<usize, SnapshotError>
210217
where
211218
T: Write,
212219
O: Serialize + Debug,
213220
{
214-
let mut buffer = Vec::new();
215-
bincode::serialize_into(&mut buffer, data)
216-
.map_err(|err| SnapshotError::Serde(err.to_string()))?;
217-
221+
// 1) Encode into an in-memory buffer
222+
let mut buf = Vec::new();
223+
bincode::serde::encode_into_std_write(data, &mut buf, BINCODE_CONFIG)
224+
.map_err(|err| match err {
225+
// Ran out of room while encoding
226+
EncodeError::UnexpectedEnd =>
227+
SnapshotError::Io(libc::EIO),
228+
229+
// Underlying IO failure during encode (index tells how many bytes got written)
230+
EncodeError::Io { inner, .. } =>
231+
SnapshotError::Io(inner.raw_os_error().unwrap_or(libc::EIO)),
232+
233+
// Any other encode error we surface as Serde
234+
other =>
235+
SnapshotError::Serde(other.to_string()),
236+
})?;
237+
238+
// 2) Flush that buffer to the target writer
218239
writer
219-
.write_all(&buffer)
220-
.map_err(|err| SnapshotError::Serde(err.to_string()))?;
240+
.write_all(&buf)
241+
.map_err(|io_err| SnapshotError::Io(io_err.raw_os_error().unwrap_or(libc::EIO)))?;
221242

222243
Ok(buffer.len())
223244
// bincode::serialize_into(writer, data).map_err(|err| SnapshotError::Serde(err.to_string()))

0 commit comments

Comments
 (0)