Skip to content

Commit 1bb9d18

Browse files
committed
refactor: centralize GuestMemoryMmap creation
In this day and age, Firecracker supports theoretically 4 different ways of backing guest memory: 1. Normal MAP_ANONYMOUS | MAP_PRIVATE memory 2. memfd backed memory, mapped as shared 3. direct mapping of a snapshot file 4. MAP_ANONYMOUS again, but this time regions are described by snapshot file. We have 3 different functions for creating these different backing stores, which then call each other and vm_memory's APIs. Clean this up by consolidating these into just one function that can be called with generic memory backing options, plus 3 wrappers for the three actually used ways of backing memory. For this, hoist up the hugepages/file-based restore incompatibility check, as with a dedicated function for dealing with the "snapshot restored by mapping file" case, this function simply will not take a huge pages argument, so we have to check this somewhere else. Signed-off-by: Patrick Roy <[email protected]>
1 parent 45ad785 commit 1bb9d18

File tree

7 files changed

+134
-261
lines changed

7 files changed

+134
-261
lines changed

src/vmm/src/devices/virtio/block/vhost_user/device.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ mod tests {
378378
use crate::devices::virtio::block::virtio::device::FileEngineType;
379379
use crate::devices::virtio::mmio::VIRTIO_MMIO_INT_CONFIG;
380380
use crate::test_utils::create_tmp_socket;
381-
use crate::vstate::memory::{FileOffset, GuestAddress, GuestMemoryExtension};
381+
use crate::vstate::memory::{GuestAddress, GuestMemoryExtension};
382382

383383
#[test]
384384
fn test_from_config() {
@@ -778,12 +778,10 @@ mod tests {
778778
let region_size = 0x10000;
779779
let file = TempFile::new().unwrap().into_file();
780780
file.set_len(region_size as u64).unwrap();
781-
let regions = vec![(
782-
FileOffset::new(file.try_clone().unwrap(), 0x0),
783-
GuestAddress(0x0),
784-
region_size,
785-
)];
786-
let guest_memory = GuestMemoryMmap::from_raw_regions_file(regions, false, false).unwrap();
781+
let regions = vec![(GuestAddress(0x0), region_size)];
782+
let guest_memory =
783+
GuestMemoryMmap::create(regions.into_iter(), libc::MAP_PRIVATE, Some(file), false)
784+
.unwrap();
787785

788786
// During actiavion of the device features, memory and queues should be set and activated.
789787
vhost_block.activate(guest_memory).unwrap();

src/vmm/src/devices/virtio/block/virtio/io/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,12 @@ pub mod tests {
230230
}
231231

232232
fn create_mem() -> GuestMemoryMmap {
233-
GuestMemoryMmap::from_raw_regions(&[(GuestAddress(0), MEM_LEN)], true, HugePageConfig::None)
234-
.unwrap()
233+
GuestMemoryMmap::anonymous(
234+
[(GuestAddress(0), MEM_LEN)].into_iter(),
235+
true,
236+
HugePageConfig::None,
237+
)
238+
.unwrap()
235239
}
236240

237241
fn check_dirty_mem(mem: &GuestMemoryMmap, addr: GuestAddress, len: u32) {

src/vmm/src/devices/virtio/vhost_user.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ mod tests {
466466

467467
use super::*;
468468
use crate::test_utils::create_tmp_socket;
469-
use crate::vstate::memory::{FileOffset, GuestAddress, GuestMemoryExtension};
469+
use crate::vstate::memory::{GuestAddress, GuestMemoryExtension};
470470

471471
#[test]
472472
fn test_new() {
@@ -759,19 +759,13 @@ mod tests {
759759
let file_size = 2 * region_size;
760760
file.set_len(file_size as u64).unwrap();
761761
let regions = vec![
762-
(
763-
FileOffset::new(file.try_clone().unwrap(), 0x0),
764-
GuestAddress(0x0),
765-
region_size,
766-
),
767-
(
768-
FileOffset::new(file.try_clone().unwrap(), 0x10000),
769-
GuestAddress(0x10000),
770-
region_size,
771-
),
762+
(GuestAddress(0x0), region_size),
763+
(GuestAddress(0x10000), region_size),
772764
];
773765

774-
let guest_memory = GuestMemoryMmap::from_raw_regions_file(regions, false, false).unwrap();
766+
let guest_memory =
767+
GuestMemoryMmap::create(regions.into_iter(), libc::MAP_PRIVATE, Some(file), false)
768+
.unwrap();
775769

776770
vuh.update_mem_table(&guest_memory).unwrap();
777771

@@ -883,13 +877,11 @@ mod tests {
883877
let region_size = 0x10000;
884878
let file = TempFile::new().unwrap().into_file();
885879
file.set_len(region_size as u64).unwrap();
886-
let regions = vec![(
887-
FileOffset::new(file.try_clone().unwrap(), 0x0),
888-
GuestAddress(0x0),
889-
region_size,
890-
)];
880+
let regions = vec![(GuestAddress(0x0), region_size)];
891881

892-
let guest_memory = GuestMemoryMmap::from_raw_regions_file(regions, false, false).unwrap();
882+
let guest_memory =
883+
GuestMemoryMmap::create(regions.into_iter(), libc::MAP_PRIVATE, Some(file), false)
884+
.unwrap();
893885

894886
let mut queue = Queue::new(69);
895887
queue.initialize(&guest_memory).unwrap();

src/vmm/src/persist.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -448,16 +448,19 @@ pub fn restore_from_snapshot(
448448
let mem_state = &microvm_state.memory_state;
449449

450450
let (guest_memory, uffd) = match params.mem_backend.backend_type {
451-
MemBackendType::File => (
452-
guest_memory_from_file(
453-
mem_backend_path,
454-
mem_state,
455-
track_dirty_pages,
456-
vm_resources.machine_config.huge_pages,
451+
MemBackendType::File => {
452+
if vm_resources.machine_config.huge_pages.is_hugetlbfs() {
453+
return Err(RestoreFromSnapshotGuestMemoryError::File(
454+
GuestMemoryFromFileError::HugetlbfsSnapshot,
455+
)
456+
.into());
457+
}
458+
(
459+
guest_memory_from_file(mem_backend_path, mem_state, track_dirty_pages)
460+
.map_err(RestoreFromSnapshotGuestMemoryError::File)?,
461+
None,
457462
)
458-
.map_err(RestoreFromSnapshotGuestMemoryError::File)?,
459-
None,
460-
),
463+
}
461464
MemBackendType::Uffd => guest_memory_from_uffd(
462465
mem_backend_path,
463466
mem_state,
@@ -513,17 +516,17 @@ pub enum GuestMemoryFromFileError {
513516
File(#[from] std::io::Error),
514517
/// Failed to restore guest memory: {0}
515518
Restore(#[from] MemoryError),
519+
/// Cannot restore hugetlbfs backed snapshot by mapping the memory file. Please use uffd.
520+
HugetlbfsSnapshot,
516521
}
517522

518523
fn guest_memory_from_file(
519524
mem_file_path: &Path,
520525
mem_state: &GuestMemoryState,
521526
track_dirty_pages: bool,
522-
huge_pages: HugePageConfig,
523527
) -> Result<GuestMemoryMmap, GuestMemoryFromFileError> {
524528
let mem_file = File::open(mem_file_path)?;
525-
let guest_mem =
526-
GuestMemoryMmap::from_state(Some(&mem_file), mem_state, track_dirty_pages, huge_pages)?;
529+
let guest_mem = GuestMemoryMmap::snapshot_file(mem_file, mem_state, track_dirty_pages)?;
527530
Ok(guest_mem)
528531
}
529532

@@ -582,7 +585,8 @@ fn create_guest_memory(
582585
track_dirty_pages: bool,
583586
huge_pages: HugePageConfig,
584587
) -> Result<(GuestMemoryMmap, Vec<GuestRegionUffdMapping>), GuestMemoryFromUffdError> {
585-
let guest_memory = GuestMemoryMmap::from_state(None, mem_state, track_dirty_pages, huge_pages)?;
588+
let guest_memory =
589+
GuestMemoryMmap::anonymous(mem_state.regions(), track_dirty_pages, huge_pages)?;
586590
let mut backend_mappings = Vec::with_capacity(guest_memory.num_regions());
587591
let mut offset = 0;
588592
for mem_region in guest_memory.iter() {

src/vmm/src/resources.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,8 @@ impl VmResources {
472472
)
473473
} else {
474474
let regions = crate::arch::arch_memory_regions(self.machine_config.mem_size_mib << 20);
475-
GuestMemoryMmap::from_raw_regions(
476-
&regions,
475+
GuestMemoryMmap::anonymous(
476+
regions.into_iter(),
477477
self.machine_config.track_dirty_pages,
478478
self.machine_config.huge_pages,
479479
)

src/vmm/src/test_utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn single_region_mem_at(at: u64, size: usize) -> GuestMemoryMmap {
3434

3535
/// Creates a [`GuestMemoryMmap`] with multiple regions and without dirty page tracking.
3636
pub fn multi_region_mem(regions: &[(GuestAddress, usize)]) -> GuestMemoryMmap {
37-
GuestMemoryMmap::from_raw_regions(regions, false, HugePageConfig::None)
37+
GuestMemoryMmap::anonymous(regions.iter().copied(), false, HugePageConfig::None)
3838
.expect("Cannot initialize memory")
3939
}
4040

0 commit comments

Comments
 (0)