Skip to content

Commit 03e5061

Browse files
committed
Expose memory mapping; Add optional memfile dump
1 parent 13ffca9 commit 03e5061

File tree

10 files changed

+87
-13
lines changed

10 files changed

+87
-13
lines changed

.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rust 1.85.0

src/firecracker/src/api_server/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ mod tests {
275275
Box::new(VmmAction::CreateSnapshot(CreateSnapshotParams {
276276
snapshot_type: SnapshotType::Diff,
277277
snapshot_path: PathBuf::new(),
278-
mem_file_path: PathBuf::new(),
278+
mem_file_path: Some(PathBuf::new()),
279279
})),
280280
start_time_us,
281281
);
@@ -288,7 +288,7 @@ mod tests {
288288
Box::new(VmmAction::CreateSnapshot(CreateSnapshotParams {
289289
snapshot_type: SnapshotType::Diff,
290290
snapshot_path: PathBuf::new(),
291-
mem_file_path: PathBuf::new(),
291+
mem_file_path: Some(PathBuf::new()),
292292
})),
293293
start_time_us,
294294
);

src/firecracker/src/api_server/request/snapshot.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ mod tests {
140140
let expected_config = CreateSnapshotParams {
141141
snapshot_type: SnapshotType::Diff,
142142
snapshot_path: PathBuf::from("foo"),
143-
mem_file_path: PathBuf::from("bar"),
143+
mem_file_path: Some(PathBuf::from("bar")),
144144
};
145145
assert_eq!(
146146
vmm_action_from_request(parse_put_snapshot(&Body::new(body), Some("create")).unwrap()),
@@ -154,7 +154,7 @@ mod tests {
154154
let expected_config = CreateSnapshotParams {
155155
snapshot_type: SnapshotType::Full,
156156
snapshot_path: PathBuf::from("foo"),
157-
mem_file_path: PathBuf::from("bar"),
157+
mem_file_path: Some(PathBuf::from("bar")),
158158
};
159159
assert_eq!(
160160
vmm_action_from_request(parse_put_snapshot(&Body::new(body), Some("create")).unwrap()),

src/firecracker/swagger/firecracker.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,32 @@ definitions:
996996
vmm_version:
997997
description: MicroVM hypervisor build version.
998998
type: string
999+
memory_regions:
1000+
type: array
1001+
description: The regions of the guest memory.
1002+
items:
1003+
$ref: "#/definitions/GuestMemoryRegion"
1004+
1005+
GuestMemoryRegionMapping:
1006+
type: object
1007+
description: Describes the region of guest memory that can be used for creating the memfile.
1008+
required:
1009+
- base_host_virt_addr
1010+
- size
1011+
- offset
1012+
- page_size
1013+
properties:
1014+
base_host_virt_addr:
1015+
type: integer
1016+
size:
1017+
description: The size of the region in bytes.
1018+
type: integer
1019+
offset:
1020+
description: The offset of the region in bytes.
1021+
type: integer
1022+
page_size:
1023+
description: The page size of the region in pages.
1024+
type: integer
9991025

10001026
Logger:
10011027
type: object

src/vmm/src/persist.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ pub fn create_snapshot(
162162

163163
snapshot_state_to_file(&microvm_state, &params.snapshot_path)?;
164164

165-
vmm.vm
166-
.snapshot_memory_to_file(&params.mem_file_path, params.snapshot_type)?;
165+
// Dump memory to file only if mem_file_path is specified
166+
if let Some(ref mem_file_path) = params.mem_file_path {
167+
vmm.vm
168+
.snapshot_memory_to_file(mem_file_path, params.snapshot_type)?;
169+
}
167170

168171
// We need to mark queues as dirty again for all activated devices. The reason we
169172
// do it here is because we don't mark pages as dirty during runtime

src/vmm/src/rpc_interface.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,9 +647,17 @@ impl RuntimeApiController {
647647
GetVmMachineConfig => Ok(VmmData::MachineConfiguration(
648648
self.vm_resources.machine_config.clone(),
649649
)),
650-
GetVmInstanceInfo => Ok(VmmData::InstanceInformation(
651-
self.vmm.lock().expect("Poisoned lock").instance_info(),
652-
)),
650+
GetVmInstanceInfo => {
651+
let locked_vmm = self.vmm.lock().expect("Poisoned lock");
652+
653+
let mut instance_info = locked_vmm.instance_info();
654+
655+
instance_info.memory_regions = locked_vmm
656+
.vm
657+
.guest_memory_mappings(&VmInfo::from(&self.vm_resources));
658+
659+
Ok(VmmData::InstanceInformation(instance_info))
660+
}
653661
GetVmmVersion => Ok(VmmData::VmmVersion(
654662
self.vmm.lock().expect("Poisoned lock").version(),
655663
)),
@@ -1147,7 +1155,7 @@ mod tests {
11471155
CreateSnapshotParams {
11481156
snapshot_type: SnapshotType::Full,
11491157
snapshot_path: PathBuf::new(),
1150-
mem_file_path: PathBuf::new(),
1158+
mem_file_path: Some(PathBuf::new()),
11511159
},
11521160
)));
11531161
#[cfg(target_arch = "x86_64")]

src/vmm/src/vmm_config/instance_info.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
use std::fmt::{self, Display, Formatter};
44

5+
use crate::vstate::vm::GuestMemoryRegionMapping;
56
use serde::{Serialize, ser};
67

78
/// Enumerates microVM runtime states.
@@ -46,4 +47,6 @@ pub struct InstanceInfo {
4647
pub vmm_version: String,
4748
/// The name of the application that runs the microVM.
4849
pub app_name: String,
50+
/// The regions of the guest memory.
51+
pub memory_regions: Vec<GuestMemoryRegionMapping>,
4952
}

src/vmm/src/vmm_config/snapshot.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ pub struct CreateSnapshotParams {
4444
/// Path to the file that will contain the microVM state.
4545
pub snapshot_path: PathBuf,
4646
/// Path to the file that will contain the guest memory.
47-
pub mem_file_path: PathBuf,
47+
/// If not specified, the memory is not dumped to a file.
48+
#[serde(skip_serializing_if = "Option::is_none")]
49+
pub mem_file_path: Option<PathBuf>,
4850
}
4951

5052
/// Allows for changing the mapping between tap devices and host devices

src/vmm/src/vstate/vm.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ use std::sync::Arc;
1313

1414
use kvm_bindings::{KVM_MEM_LOG_DIRTY_PAGES, kvm_userspace_memory_region};
1515
use kvm_ioctls::VmFd;
16+
use serde::{Deserialize, Serialize};
1617
use vmm_sys_util::eventfd::EventFd;
1718

1819
pub use crate::arch::{ArchVm as Vm, ArchVmError, VmState};
1920
use crate::logger::info;
20-
use crate::persist::CreateSnapshotError;
21+
use crate::persist::{CreateSnapshotError, VmInfo};
2122
use crate::utils::u64_to_usize;
2223
use crate::vmm_config::snapshot::SnapshotType;
2324
use crate::vstate::memory::{
@@ -36,6 +37,20 @@ pub struct VmCommon {
3637
pub guest_memory: GuestMemoryMmap,
3738
}
3839

40+
/// Describes the region of guest memory that can be used for creating the memfile.
41+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
42+
pub struct GuestMemoryRegionMapping {
43+
/// Base host virtual address where the guest memory contents for this region
44+
/// should be copied/populated.
45+
pub base_host_virt_addr: u64,
46+
/// Region size.
47+
pub size: usize,
48+
/// Offset in the backend file/buffer where the region contents are.
49+
pub offset: u64,
50+
/// The configured page size for this memory region.
51+
pub page_size: usize,
52+
}
53+
3954
/// Errors associated with the wrappers over KVM ioctls.
4055
/// Needs `rustfmt::skip` to make multiline comments work
4156
#[rustfmt::skip]
@@ -185,6 +200,22 @@ impl Vm {
185200
&self.common.guest_memory
186201
}
187202

203+
/// Gets the mappings for the guest memory.
204+
pub fn guest_memory_mappings(&self, vm_info: &VmInfo) -> Vec<GuestMemoryRegionMapping> {
205+
let mut offset = 0;
206+
let mut mappings = Vec::new();
207+
for mem_region in self.guest_memory().iter() {
208+
mappings.push(GuestMemoryRegionMapping {
209+
base_host_virt_addr: mem_region.as_ptr() as u64,
210+
size: mem_region.size(),
211+
offset,
212+
page_size: vm_info.huge_pages.page_size(),
213+
});
214+
offset += mem_region.size() as u64;
215+
}
216+
mappings
217+
}
218+
188219
/// Resets the KVM dirty bitmap for each of the guest's memory regions.
189220
pub fn reset_dirty_bitmap(&self) {
190221
self.guest_memory()

src/vmm/tests/integration_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ fn verify_create_snapshot(is_diff: bool) -> (TempFile, TempFile) {
215215
let snapshot_params = CreateSnapshotParams {
216216
snapshot_type,
217217
snapshot_path: snapshot_file.as_path().to_path_buf(),
218-
mem_file_path: memory_file.as_path().to_path_buf(),
218+
mem_file_path: Some(memory_file.as_path().to_path_buf()),
219219
};
220220

221221
controller

0 commit comments

Comments
 (0)