Skip to content

Commit 482a65c

Browse files
committed
fix: only reset dirty bitmap if all regions were dumped successfully
When taking a diff snapshot, Firecracker resets the dirty bitmap of each guest memory region if the region itself was successfully dumped to the snapshot memory file. This is wrong, because a later region might fail, and then some regions will have their dirty bitmap reset, yet no snapshot was successfully taken, meaning a failure during diff snapshot taking will forever corrupt the dirty bitmap. Fix this by only reset the dirty bitmap of all regions after (and if!) all regions were successfully dumped to the file. Signed-off-by: Patrick Roy <[email protected]>
1 parent 477200c commit 482a65c

File tree

3 files changed

+11
-11
lines changed

3 files changed

+11
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ and this project adheres to
4444
the `SendCtrlAltDel` command not working for ACPI-enabled guest kernels, by
4545
dropping the i8042.nopnp argument from the default kernel command line
4646
Firecracker constructs.
47+
- #[???](???): Fix failure during diff snapshot creation corrupting internal
48+
state about which pages were dirtied since the last snapshot, meaning no
49+
further diff snapshots could ever be taken, even if the error is transient.
4750

4851
## [1.11.0]
4952

src/vmm/src/vstate/memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,6 @@ impl GuestMemoryExtension for GuestMemoryMmap {
273273

274274
if write_result.is_err() {
275275
self.store_dirty_bitmap(dirty_bitmap, page_size);
276-
} else {
277-
self.reset_dirty();
278276
}
279277

280278
write_result.map_err(MemoryError::WriteMemory)
@@ -622,6 +620,7 @@ mod tests {
622620

623621
let mut file = TempFile::new().unwrap().into_file();
624622
guest_memory.dump_dirty(&mut file, &dirty_bitmap).unwrap();
623+
guest_memory.reset_dirty();
625624

626625
// We can restore from this because this is the first dirty dump.
627626
let restored_guest_memory = GuestMemoryMmap::from_regions(
@@ -656,6 +655,7 @@ mod tests {
656655
.unwrap();
657656

658657
guest_memory.dump_dirty(&mut reader, &dirty_bitmap).unwrap();
658+
guest_memory.reset_dirty();
659659

660660
// Check that only the dirty regions are dumped.
661661
let mut diff_file_content = Vec::new();

src/vmm/src/vstate/vm.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -262,18 +262,15 @@ impl Vm {
262262
match snapshot_type {
263263
SnapshotType::Diff => {
264264
let dirty_bitmap = self.get_dirty_bitmap().map_err(DirtyBitmap)?;
265-
self.guest_memory().dump_dirty(&mut file, &dirty_bitmap)
265+
self.guest_memory().dump_dirty(&mut file, &dirty_bitmap)?;
266266
}
267267
SnapshotType::Full => {
268-
let dump_res = self.guest_memory().dump(&mut file);
269-
if dump_res.is_ok() {
270-
self.reset_dirty_bitmap();
271-
self.guest_memory().reset_dirty();
272-
}
273-
274-
dump_res
268+
self.guest_memory().dump(&mut file)?;
269+
self.reset_dirty_bitmap();
275270
}
276-
}?;
271+
};
272+
273+
self.guest_memory().reset_dirty();
277274

278275
file.flush()
279276
.map_err(|err| MemoryBackingFile("flush", err))?;

0 commit comments

Comments
 (0)