Skip to content

Commit 10fe1ac

Browse files
committed
refactor: cleanup vmm::snapshot module
Implement the suggestions from #4523 to give a cleaner API for the snapshot module. Conceptually, the change is that we now store the thing we are snapshotting inside of the `Snapshot` struct. Implementation-wise, this allows us to deserialize the snapshot data in a single pass (instead of having to read it twice, once for deserialization and once for CRC validation), which means we do not have to first query the snapshot file for the size of the snapshot. Closes #4691, #4523, #5195 Signed-off-by: Patrick Roy <[email protected]>
1 parent 816d905 commit 10fe1ac

File tree

25 files changed

+233
-318
lines changed

25 files changed

+233
-318
lines changed

src/firecracker/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use vmm::persist::SNAPSHOT_VERSION;
2828
use vmm::resources::VmResources;
2929
use vmm::seccomp::BpfThreadMap;
3030
use vmm::signal_handler::register_signal_handlers;
31-
use vmm::snapshot::{Snapshot, SnapshotError};
31+
use vmm::snapshot::{SnapshotError, get_format_version};
3232
use vmm::vmm_config::instance_info::{InstanceInfo, VmState};
3333
use vmm::vmm_config::metrics::{MetricsConfig, MetricsConfigError, init_metrics};
3434
use vmm::{EventManager, FcExitCode, HTTP_MAX_PAYLOAD_SIZE};
@@ -546,8 +546,8 @@ fn print_snapshot_data_format(snapshot_path: &str) -> Result<(), SnapshotVersion
546546
let mut snapshot_reader =
547547
File::open(snapshot_path).map_err(SnapshotVersionError::OpenSnapshot)?;
548548

549-
let data_format_version = Snapshot::get_format_version(&mut snapshot_reader)
550-
.map_err(SnapshotVersionError::SnapshotVersion)?;
549+
let data_format_version =
550+
get_format_version(&mut snapshot_reader).map_err(SnapshotVersionError::SnapshotVersion)?;
551551

552552
println!("v{}", data_format_version);
553553
Ok(())

src/snapshot-editor/src/edit_vmstate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ fn edit(
5151
output_path: &PathBuf,
5252
f: impl Fn(MicrovmState) -> Result<MicrovmState, EditVmStateError>,
5353
) -> Result<(), EditVmStateError> {
54-
let (microvm_state, _) = open_vmstate(vmstate_path)?;
55-
let microvm_state = f(microvm_state)?;
54+
let snapshot = open_vmstate(vmstate_path)?;
55+
let microvm_state = f(snapshot.data)?;
5656
save_vmstate(microvm_state, output_path)?;
5757
Ok(())
5858
}

src/snapshot-editor/src/info.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
use std::path::PathBuf;
55

66
use clap::Subcommand;
7-
use semver::Version;
87
use vmm::persist::MicrovmState;
8+
use vmm::snapshot::Snapshot;
99

1010
use crate::utils::*;
1111

@@ -50,27 +50,27 @@ pub fn info_vmstate_command(command: InfoVmStateSubCommand) -> Result<(), InfoVm
5050

5151
fn info(
5252
vmstate_path: &PathBuf,
53-
f: impl Fn(&MicrovmState, Version) -> Result<(), InfoVmStateError>,
53+
f: impl Fn(&Snapshot<MicrovmState>) -> Result<(), InfoVmStateError>,
5454
) -> Result<(), InfoVmStateError> {
55-
let (vmstate, version) = open_vmstate(vmstate_path)?;
56-
f(&vmstate, version)?;
55+
let snapshot = open_vmstate(vmstate_path)?;
56+
f(&snapshot)?;
5757
Ok(())
5858
}
5959

60-
fn info_version(_: &MicrovmState, version: Version) -> Result<(), InfoVmStateError> {
61-
println!("v{version}");
60+
fn info_version(snapshot: &Snapshot<MicrovmState>) -> Result<(), InfoVmStateError> {
61+
println!("v{}", snapshot.version());
6262
Ok(())
6363
}
6464

65-
fn info_vcpu_states(state: &MicrovmState, _: Version) -> Result<(), InfoVmStateError> {
66-
for (i, state) in state.vcpu_states.iter().enumerate() {
65+
fn info_vcpu_states(snapshot: &Snapshot<MicrovmState>) -> Result<(), InfoVmStateError> {
66+
for (i, state) in snapshot.data.vcpu_states.iter().enumerate() {
6767
println!("vcpu {i}:");
6868
println!("{state:#?}");
6969
}
7070
Ok(())
7171
}
7272

73-
fn info_vmstate(vmstate: &MicrovmState, _version: Version) -> Result<(), InfoVmStateError> {
74-
println!("{vmstate:#?}");
73+
fn info_vmstate(snapshot: &Snapshot<MicrovmState>) -> Result<(), InfoVmStateError> {
74+
println!("{:#?}", snapshot.data);
7575
Ok(())
7676
}

src/snapshot-editor/src/utils.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@
44
use std::fs::{File, OpenOptions};
55
use std::path::PathBuf;
66

7-
use semver::Version;
8-
use vmm::persist::{MicrovmState, SNAPSHOT_VERSION};
7+
use vmm::persist::MicrovmState;
98
use vmm::snapshot::Snapshot;
10-
use vmm::utils::u64_to_usize;
119

1210
// Some errors are only used in aarch64 code
1311
#[allow(unused)]
1412
#[derive(Debug, thiserror::Error, displaydoc::Display)]
1513
pub enum UtilsError {
1614
/// Can not open snapshot file: {0}
1715
VmStateFileOpen(std::io::Error),
18-
/// Can not retrieve metadata for snapshot file: {0}
19-
VmStateFileMeta(std::io::Error),
2016
/// Can not load snapshot: {0}
2117
VmStateLoad(vmm::snapshot::SnapshotError),
2218
/// Can not open output file: {0}
@@ -26,11 +22,9 @@ pub enum UtilsError {
2622
}
2723

2824
#[allow(unused)]
29-
pub fn open_vmstate(snapshot_path: &PathBuf) -> Result<(MicrovmState, Version), UtilsError> {
25+
pub fn open_vmstate(snapshot_path: &PathBuf) -> Result<Snapshot<MicrovmState>, UtilsError> {
3026
let mut snapshot_reader = File::open(snapshot_path).map_err(UtilsError::VmStateFileOpen)?;
31-
let metadata = std::fs::metadata(snapshot_path).map_err(UtilsError::VmStateFileMeta)?;
32-
let snapshot_len = u64_to_usize(metadata.len());
33-
Snapshot::load(&mut snapshot_reader, snapshot_len).map_err(UtilsError::VmStateLoad)
27+
Snapshot::load(&mut snapshot_reader).map_err(UtilsError::VmStateLoad)
3428
}
3529

3630
// This method is used only in aarch64 code so far
@@ -42,9 +36,9 @@ pub fn save_vmstate(microvm_state: MicrovmState, output_path: &PathBuf) -> Resul
4236
.truncate(true)
4337
.open(output_path)
4438
.map_err(UtilsError::OutputFileOpen)?;
45-
let mut snapshot = Snapshot::new(SNAPSHOT_VERSION);
39+
let mut snapshot = Snapshot::new(microvm_state);
4640
snapshot
47-
.save(&mut output_file, &microvm_state)
41+
.save(&mut output_file)
4842
.map_err(UtilsError::VmStateSave)?;
4943
Ok(())
5044
}

src/vmm/src/arch/aarch64/regs.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,8 @@ mod tests {
546546

547547
let mut buf = vec![0; 10000];
548548

549-
Snapshot::serialize(&mut buf.as_mut_slice(), &v).unwrap();
550-
let restored: Aarch64RegisterVec = Snapshot::deserialize(&mut buf.as_slice()).unwrap();
549+
Snapshot::new(&v).save(&mut buf.as_mut_slice()).unwrap();
550+
let restored: Aarch64RegisterVec = Snapshot::load(&mut buf.as_slice()).unwrap().data;
551551

552552
for (old, new) in v.iter().zip(restored.iter()) {
553553
assert_eq!(old, new);
@@ -572,11 +572,11 @@ mod tests {
572572

573573
let mut buf = vec![0; 10000];
574574

575-
Snapshot::serialize(&mut buf.as_mut_slice(), &v).unwrap();
575+
Snapshot::new(&v).save(&mut buf.as_mut_slice()).unwrap();
576576

577577
// Total size of registers according IDs are 16 + 16 = 32,
578578
// but actual data size is 8 + 16 = 24.
579-
Snapshot::deserialize::<_, Aarch64RegisterVec>(&mut buf.as_slice()).unwrap_err();
579+
Snapshot::<Aarch64RegisterVec>::load(&mut buf.as_slice()).unwrap_err();
580580
}
581581

582582
#[test]
@@ -595,10 +595,10 @@ mod tests {
595595

596596
let mut buf = vec![0; 10000];
597597

598-
Snapshot::serialize(&mut buf.as_mut_slice(), &v).unwrap();
598+
Snapshot::new(v).save(&mut buf.as_mut_slice()).unwrap();
599599

600600
// 4096 bit wide registers are not supported.
601-
Snapshot::deserialize::<_, Aarch64RegisterVec>(&mut buf.as_slice()).unwrap_err();
601+
Snapshot::<Aarch64RegisterVec>::load(&mut buf.as_slice()).unwrap_err();
602602
}
603603

604604
#[test]

src/vmm/src/arch/x86_64/vm.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,10 @@ mod tests {
318318
let (_, mut vm) = setup_vm_with_memory(0x1000);
319319
vm.setup_irqchip().unwrap();
320320
let state = vm.save_state().unwrap();
321-
Snapshot::serialize(&mut snapshot_data.as_mut_slice(), &state).unwrap();
322-
let restored_state: VmState = Snapshot::deserialize(&mut snapshot_data.as_slice()).unwrap();
321+
Snapshot::new(state)
322+
.save(&mut snapshot_data.as_mut_slice())
323+
.unwrap();
324+
let restored_state: VmState = Snapshot::load(&mut snapshot_data.as_slice()).unwrap().data;
323325

324326
vm.restore_state(&restored_state).unwrap();
325327
}

src/vmm/src/device_manager/pci_mngr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ mod tests {
645645
let entropy_config = EntropyDeviceConfig::default();
646646
insert_entropy_device(&mut vmm, &mut cmdline, &mut event_manager, entropy_config);
647647

648-
Snapshot::serialize(&mut buf.as_mut_slice(), &vmm.device_manager.save()).unwrap();
648+
Snapshot::new(vmm.device_manager.save()).save(&mut buf.as_mut_slice()).unwrap();
649649
}
650650

651651
tmp_sock_file.remove().unwrap();
@@ -657,7 +657,7 @@ mod tests {
657657
// object and calling default_vmm() is the easiest way to create one.
658658
let vmm = default_vmm();
659659
let device_manager_state: device_manager::DevicesState =
660-
Snapshot::deserialize(&mut buf.as_slice()).unwrap();
660+
Snapshot::load(&mut buf.as_slice()).unwrap().data;
661661
let vm_resources = &mut VmResources::default();
662662
let restore_args = PciDevicesConstructorArgs {
663663
vm: vmm.vm.clone(),

src/vmm/src/device_manager/persist.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,15 +676,17 @@ mod tests {
676676
let entropy_config = EntropyDeviceConfig::default();
677677
insert_entropy_device(&mut vmm, &mut cmdline, &mut event_manager, entropy_config);
678678

679-
Snapshot::serialize(&mut buf.as_mut_slice(), &vmm.device_manager.save()).unwrap();
679+
Snapshot::new(vmm.device_manager.save())
680+
.save(&mut buf.as_mut_slice())
681+
.unwrap();
680682
}
681683

682684
tmp_sock_file.remove().unwrap();
683685

684686
let mut event_manager = EventManager::new().expect("Unable to create EventManager");
685687
let vmm = default_vmm();
686688
let device_manager_state: device_manager::DevicesState =
687-
Snapshot::deserialize(&mut buf.as_slice()).unwrap();
689+
Snapshot::load(&mut buf.as_slice()).unwrap().data;
688690
let vm_resources = &mut VmResources::default();
689691
let restore_args = MMIODevManagerConstructorArgs {
690692
mem: vmm.vm.guest_memory(),

src/vmm/src/devices/virtio/balloon/persist.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,17 @@ mod tests {
187187
// Create and save the balloon device.
188188
let balloon = Balloon::new(0x42, false, 2, false).unwrap();
189189

190-
Snapshot::serialize(&mut mem.as_mut_slice(), &balloon.save()).unwrap();
190+
Snapshot::new(balloon.save())
191+
.save(&mut mem.as_mut_slice())
192+
.unwrap();
191193

192194
// Deserialize and restore the balloon device.
193195
let restored_balloon = Balloon::restore(
194196
BalloonConstructorArgs {
195197
mem: guest_mem,
196198
restored_from_file: true,
197199
},
198-
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),
200+
&Snapshot::load(&mut mem.as_slice()).unwrap().data,
199201
)
200202
.unwrap();
201203

src/vmm/src/devices/virtio/block/virtio/persist.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ mod tests {
171171
// Save the block device.
172172
let mut mem = vec![0; 4096];
173173

174-
Snapshot::serialize(&mut mem.as_mut_slice(), &block.save()).unwrap();
174+
Snapshot::new(block.save())
175+
.save(&mut mem.as_mut_slice())
176+
.unwrap();
175177
}
176178

177179
#[test]
@@ -214,12 +216,14 @@ mod tests {
214216
// Save the block device.
215217
let mut mem = vec![0; 4096];
216218

217-
Snapshot::serialize(&mut mem.as_mut_slice(), &block.save()).unwrap();
219+
Snapshot::new(block.save())
220+
.save(&mut mem.as_mut_slice())
221+
.unwrap();
218222

219223
// Restore the block device.
220224
let restored_block = VirtioBlock::restore(
221225
BlockConstructorArgs { mem: guest_mem },
222-
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),
226+
&Snapshot::load(&mut mem.as_slice()).unwrap().data,
223227
)
224228
.unwrap();
225229

0 commit comments

Comments
 (0)