Skip to content

Commit 112ceb6

Browse files
committed
Wire up huge pages support with snapshot feature
We store the huge pages configuration in the snapshot's vmstate file, and enforce that a snapshot gets restored with the same hugepages configuration with which it was taken (for simplicity reasons). Signed-off-by: Patrick Roy <[email protected]>
1 parent 8bc45d3 commit 112ceb6

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

src/vmm/src/persist.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::logger::{info, warn};
3232
use crate::resources::VmResources;
3333
use crate::vmm_config::boot_source::BootSourceConfig;
3434
use crate::vmm_config::instance_info::InstanceInfo;
35-
use crate::vmm_config::machine_config::{MachineConfigUpdate, VmConfigError};
35+
use crate::vmm_config::machine_config::{HugePageConfig, MachineConfigUpdate, VmConfigError};
3636
use crate::vmm_config::snapshot::{
3737
CreateSnapshotParams, LoadSnapshotParams, MemBackendType, SnapshotType,
3838
};
@@ -54,6 +54,8 @@ pub struct VmInfo {
5454
pub cpu_template: StaticCpuTemplate,
5555
/// Boot source information.
5656
pub boot_source: BootSourceConfig,
57+
/// Huge page configuration
58+
pub huge_pages: HugePageConfig,
5759
}
5860

5961
impl From<&VmResources> for VmInfo {
@@ -63,6 +65,7 @@ impl From<&VmResources> for VmInfo {
6365
smt: value.vm_config.smt,
6466
cpu_template: StaticCpuTemplate::from(&value.vm_config.cpu_template),
6567
boot_source: value.boot_source_config().clone(),
68+
huge_pages: value.vm_config.huge_pages,
6669
}
6770
}
6871
}
@@ -399,7 +402,7 @@ pub fn restore_from_snapshot(
399402
smt: Some(microvm_state.vm_info.smt),
400403
cpu_template: Some(microvm_state.vm_info.cpu_template),
401404
track_dirty_pages: Some(track_dirty_pages),
402-
huge_pages: None, // TODO: snapshot integration
405+
huge_pages: Some(microvm_state.vm_info.huge_pages),
403406
})
404407
.map_err(BuildMicrovmFromSnapshotError::VmUpdateConfig)?;
405408

@@ -411,8 +414,13 @@ pub fn restore_from_snapshot(
411414

412415
let (guest_memory, uffd) = match params.mem_backend.backend_type {
413416
MemBackendType::File => (
414-
guest_memory_from_file(mem_backend_path, mem_state, track_dirty_pages)
415-
.map_err(RestoreFromSnapshotGuestMemoryError::File)?,
417+
guest_memory_from_file(
418+
mem_backend_path,
419+
mem_state,
420+
track_dirty_pages,
421+
vm_resources.vm_config.huge_pages,
422+
)
423+
.map_err(RestoreFromSnapshotGuestMemoryError::File)?,
416424
None,
417425
),
418426
MemBackendType::Uffd => guest_memory_from_uffd(
@@ -422,6 +430,7 @@ pub fn restore_from_snapshot(
422430
// We enable the UFFD_FEATURE_EVENT_REMOVE feature only if a balloon device
423431
// is present in the microVM state.
424432
microvm_state.device_states.balloon_device.is_some(),
433+
vm_resources.vm_config.huge_pages,
425434
)
426435
.map_err(RestoreFromSnapshotGuestMemoryError::Uffd)?,
427436
};
@@ -475,9 +484,11 @@ fn guest_memory_from_file(
475484
mem_file_path: &Path,
476485
mem_state: &GuestMemoryState,
477486
track_dirty_pages: bool,
487+
huge_pages: HugePageConfig,
478488
) -> Result<GuestMemoryMmap, GuestMemoryFromFileError> {
479489
let mem_file = File::open(mem_file_path)?;
480-
let guest_mem = GuestMemoryMmap::from_state(Some(&mem_file), mem_state, track_dirty_pages)?;
490+
let guest_mem =
491+
GuestMemoryMmap::from_state(Some(&mem_file), mem_state, track_dirty_pages, huge_pages)?;
481492
Ok(guest_mem)
482493
}
483494

@@ -501,8 +512,9 @@ fn guest_memory_from_uffd(
501512
mem_state: &GuestMemoryState,
502513
track_dirty_pages: bool,
503514
enable_balloon: bool,
515+
huge_pages: HugePageConfig,
504516
) -> Result<(GuestMemoryMmap, Option<Uffd>), GuestMemoryFromUffdError> {
505-
let guest_memory = GuestMemoryMmap::from_state(None, mem_state, track_dirty_pages)?;
517+
let guest_memory = GuestMemoryMmap::from_state(None, mem_state, track_dirty_pages, huge_pages)?;
506518

507519
let mut uffd_builder = UffdBuilder::new();
508520

src/vmm/src/rpc_interface.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,7 @@ mod tests {
10691069
smt: value.vm_config.smt,
10701070
cpu_template: StaticCpuTemplate::from(&value.vm_config.cpu_template),
10711071
boot_source: value.boot_source_config().clone(),
1072+
huge_pages: value.vm_config.huge_pages,
10721073
}
10731074
}
10741075
}

src/vmm/src/vstate/memory.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ pub enum MemoryError {
5252
MemfdSetLen(std::io::Error),
5353
/// Failed to use madvise to enable THP: {0:?}
5454
Madvise(std::io::Error),
55+
/// Cannot restore hugetlbfs backed snapshot by maping the memory file. Please use uffd.
56+
HugetlbfsSnapshot,
5557
}
5658

5759
/// Defines the interface for snapshotting memory.
@@ -87,6 +89,7 @@ where
8789
file: Option<&File>,
8890
state: &GuestMemoryState,
8991
track_dirty_pages: bool,
92+
huge_pages: HugePageConfig,
9093
) -> Result<Self, MemoryError>;
9194

9295
/// Describes GuestMemoryMmap through a GuestMemoryState struct.
@@ -227,9 +230,14 @@ impl GuestMemoryExtension for GuestMemoryMmap {
227230
file: Option<&File>,
228231
state: &GuestMemoryState,
229232
track_dirty_pages: bool,
233+
huge_pages: HugePageConfig,
230234
) -> Result<Self, MemoryError> {
231235
match file {
232236
Some(f) => {
237+
if huge_pages.is_hugetlbfs() {
238+
return Err(MemoryError::HugetlbfsSnapshot);
239+
}
240+
233241
let regions = state
234242
.regions
235243
.iter()
@@ -242,15 +250,20 @@ impl GuestMemoryExtension for GuestMemoryMmap {
242250
.collect::<Result<Vec<_>, std::io::Error>>()
243251
.map_err(MemoryError::FileError)?;
244252

245-
Self::from_raw_regions_file(regions, track_dirty_pages, false, false)
253+
Self::from_raw_regions_file(
254+
regions,
255+
track_dirty_pages,
256+
false,
257+
huge_pages == HugePageConfig::Thp,
258+
)
246259
}
247260
None => {
248261
let regions = state
249262
.regions
250263
.iter()
251264
.map(|r| (GuestAddress(r.base_address), r.size))
252265
.collect::<Vec<_>>();
253-
Self::from_raw_regions(&regions, track_dirty_pages, HugePageConfig::None)
266+
Self::from_raw_regions(&regions, track_dirty_pages, huge_pages)
254267
}
255268
}
256269
}
@@ -512,6 +525,25 @@ pub mod tests {
512525
}
513526
}
514527

528+
#[test]
529+
fn test_from_state() {
530+
let state = GuestMemoryState {
531+
regions: vec![GuestMemoryRegionState {
532+
base_address: 0,
533+
size: 4096,
534+
offset: 0,
535+
}],
536+
};
537+
let file = TempFile::new().unwrap().into_file();
538+
539+
// No mapping of snapshots that were taken with hugetlbfs enabled
540+
let err =
541+
GuestMemoryMmap::from_state(Some(&file), &state, false, HugePageConfig::Hugetlbfs2M)
542+
.unwrap_err();
543+
544+
assert!(matches!(err, MemoryError::HugetlbfsSnapshot), "{:?}", err);
545+
}
546+
515547
#[test]
516548
fn test_mark_dirty() {
517549
let page_size = get_page_size().unwrap();
@@ -691,8 +723,13 @@ pub mod tests {
691723
let mut memory_file = TempFile::new().unwrap().into_file();
692724
guest_memory.dump(&mut memory_file).unwrap();
693725

694-
let restored_guest_memory =
695-
GuestMemoryMmap::from_state(Some(&memory_file), &memory_state, false).unwrap();
726+
let restored_guest_memory = GuestMemoryMmap::from_state(
727+
Some(&memory_file),
728+
&memory_state,
729+
false,
730+
HugePageConfig::None,
731+
)
732+
.unwrap();
696733

697734
// Check that the region contents are the same.
698735
let mut restored_region = vec![0u8; page_size * 2];
@@ -750,7 +787,8 @@ pub mod tests {
750787

751788
// We can restore from this because this is the first dirty dump.
752789
let restored_guest_memory =
753-
GuestMemoryMmap::from_state(Some(&file), &memory_state, false).unwrap();
790+
GuestMemoryMmap::from_state(Some(&file), &memory_state, false, HugePageConfig::None)
791+
.unwrap();
754792

755793
// Check that the region contents are the same.
756794
let mut restored_region = vec![0u8; region_size];

src/vmm/tests/integration_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use vmm::utilities::mock_resources::{MockVmResources, NOISY_KERNEL_IMAGE};
1616
use vmm::utilities::test_utils::dirty_tracking_vmm;
1717
use vmm::utilities::test_utils::{create_vmm, default_vmm, default_vmm_no_boot};
1818
use vmm::vmm_config::instance_info::{InstanceInfo, VmState};
19+
use vmm::vmm_config::machine_config::HugePageConfig;
1920
use vmm::vmm_config::snapshot::{CreateSnapshotParams, SnapshotType};
2021
use vmm::{DumpCpuConfigError, EventManager, FcExitCode};
2122

@@ -242,6 +243,7 @@ fn verify_load_snapshot(snapshot_file: TempFile, memory_file: TempFile) {
242243
Some(memory_file.as_file()),
243244
&microvm_state.memory_state,
244245
false,
246+
HugePageConfig::None,
245247
)
246248
.unwrap();
247249

0 commit comments

Comments
 (0)