WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit d139fe6

Browse files
committed
Support shared mmap for running VMs
This allows us to run VMs while streaming memory changes to disk support mmap shared update log add configuration for memory backing file Progress tweaks
1 parent 876834c commit d139fe6

File tree

16 files changed

+296
-41
lines changed

16 files changed

+296
-41
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/seccomp/aarch64-unknown-linux-musl.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,19 @@
596596
}
597597
]
598598
},
599+
{
600+
"syscall": "msync",
601+
"comment": "Used to sync memory from mmap to disk",
602+
"args": [
603+
{
604+
"index": 2,
605+
"type": "dword",
606+
"op": "eq",
607+
"val": 4,
608+
"comment": "MS_SYNC"
609+
}
610+
]
611+
},
599612
{
600613
"syscall": "rt_sigaction",
601614
"comment": "rt_sigaction is used by libc::abort during a panic to install the default handler for SIGABRT",

resources/seccomp/x86_64-unknown-linux-musl.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,19 @@
248248
}
249249
]
250250
},
251+
{
252+
"syscall": "msync",
253+
"comment": "Used to sync memory from mmap to disk",
254+
"args": [
255+
{
256+
"index": 2,
257+
"type": "dword",
258+
"op": "eq",
259+
"val": 4,
260+
"comment": "MS_SYNC"
261+
}
262+
]
263+
},
251264
{
252265
"syscall": "rt_sigaction",
253266
"comment": "rt_sigaction is used by libc::abort during a panic to install the default handler for SIGABRT",

src/api_server/src/parsed_request.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::request::logger::parse_put_logger;
1414
use crate::request::machine_configuration::{
1515
parse_get_machine_config, parse_patch_machine_config, parse_put_machine_config,
1616
};
17+
use crate::request::memory_backing_file::parse_put_memory_backing_file;
1718
use crate::request::metrics::parse_put_metrics;
1819
use crate::request::mmds::{parse_get_mmds, parse_patch_mmds, parse_put_mmds};
1920
use crate::request::net::{parse_patch_net, parse_put_net};
@@ -114,6 +115,7 @@ impl ParsedRequest {
114115
(Method::Put, "network-interfaces", Some(body)) => {
115116
parse_put_net(body, path_tokens.get(1))
116117
}
118+
(Method::Put, "memory-backing-file", Some(body)) => parse_put_memory_backing_file(body),
117119
(Method::Put, "shutdown-internal", None) => {
118120
Ok(ParsedRequest::new(RequestAction::ShutdownInternal))
119121
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use super::super::VmmAction;
5+
use crate::parsed_request::{Error, ParsedRequest};
6+
use crate::request::Body;
7+
use logger::{IncMetric, METRICS};
8+
use vmm::vmm_config::memory_backing_file::MemoryBackingFileConfig;
9+
10+
pub(crate) fn parse_put_memory_backing_file(body: &Body) -> Result<ParsedRequest, Error> {
11+
METRICS.put_api_requests.memory_backing_file_cfg_count.inc();
12+
Ok(ParsedRequest::new_sync(VmmAction::SetMemoryBackingFile(
13+
serde_json::from_slice::<MemoryBackingFileConfig>(body.raw()).map_err(|e| {
14+
METRICS.put_api_requests.memory_backing_file_cfg_fails.inc();
15+
Error::SerdeJson(e)
16+
})?,
17+
)))
18+
}
19+
20+
#[cfg(test)]
21+
mod tests {
22+
use std::path::PathBuf;
23+
24+
use super::*;
25+
26+
#[test]
27+
fn test_parse_memory_backing_file() {
28+
assert!(parse_put_memory_backing_file(&Body::new("invalid_payload")).is_err());
29+
30+
let body = r#"{
31+
"path": "./memory.snap"
32+
}"#;
33+
let same_body = MemoryBackingFileConfig {
34+
path: PathBuf::from("./memory.snap"),
35+
};
36+
let result = parse_put_memory_backing_file(&Body::new(body));
37+
assert!(result.is_ok());
38+
let parsed_req = result.unwrap_or_else(|_e| panic!("Failed test."));
39+
40+
assert!(parsed_req == ParsedRequest::new_sync(VmmAction::SetMemoryBackingFile(same_body)));
41+
}
42+
}

src/api_server/src/request/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod drive;
88
pub mod instance_info;
99
pub mod logger;
1010
pub mod machine_configuration;
11+
pub mod memory_backing_file;
1112
pub mod metrics;
1213
pub mod mmds;
1314
pub mod net;

src/api_server/swagger/firecracker.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,29 @@ paths:
350350
description: Internal server error
351351
schema:
352352
$ref: "#/definitions/Error"
353+
354+
/memory-backing-file:
355+
put:
356+
summary: Configures a memory backing file to sync the memory changes to during the runtime of the vm
357+
operationId: putMemoryBackingFile
358+
parameters:
359+
- name: body
360+
in: body
361+
description: Path to memory backing file
362+
required: true
363+
schema:
364+
$ref: "#/definitions/MemoryBackingFile"
365+
responses:
366+
204:
367+
description: Memory backing file configured
368+
400:
369+
description: Memory backing file failed
370+
schema:
371+
$ref: "#/definitions/Error"
372+
default:
373+
description: Internal server error.
374+
schema:
375+
$ref: "#/definitions/Error"
353376

354377
/metrics:
355378
put:
@@ -1047,6 +1070,14 @@ definitions:
10471070
tx_rate_limiter:
10481071
$ref: "#/definitions/RateLimiter"
10491072

1073+
MemoryBackingFile:
1074+
type: object
1075+
required:
1076+
- path
1077+
properties:
1078+
path:
1079+
type: string
1080+
10501081
PartialDrive:
10511082
type: object
10521083
required:

src/logger/src/metrics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ pub struct PutRequestsMetrics {
399399
pub machine_cfg_count: SharedIncMetric,
400400
/// Number of failures in configuring the machine.
401401
pub machine_cfg_fails: SharedIncMetric,
402+
/// Number of PUTs for setting memory backing file.
403+
pub memory_backing_file_cfg_count: SharedIncMetric,
404+
/// Number of failures in configuring the machine.
405+
pub memory_backing_file_cfg_fails: SharedIncMetric,
402406
/// Number of PUTs for initializing the metrics system.
403407
pub metrics_count: SharedIncMetric,
404408
/// Number of failures in initializing the metrics system.

src/vm-memory/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub fn create_guest_memory(
116116
for region in regions {
117117
let flags = match region.0 {
118118
None => libc::MAP_NORESERVE | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
119-
Some(_) => libc::MAP_NORESERVE | libc::MAP_PRIVATE,
119+
Some(_) => libc::MAP_NORESERVE | libc::MAP_SHARED,
120120
};
121121

122122
let mmap_region =

src/vmm/src/builder.rs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ use libc::EFD_NONBLOCK;
1212
use logger::METRICS;
1313
use std::convert::TryFrom;
1414
use std::fmt::{Display, Formatter};
15+
use std::fs::File;
1516
use std::io::{self, Read, Seek, SeekFrom};
1617
use std::os::unix::io::{AsRawFd, RawFd};
1718
use std::sync::{Arc, Mutex};
19+
use vm_memory::FileOffset;
1820
use vm_superio::Serial;
1921

2022
#[cfg(target_arch = "aarch64")]
@@ -23,6 +25,7 @@ use crate::construct_kvm_mpidrs;
2325
use crate::device_manager::legacy::PortIODeviceManager;
2426
use crate::device_manager::mmio::MMIODeviceManager;
2527
use crate::device_manager::persist::MMIODevManagerConstructorArgs;
28+
use crate::persist::MemoryDescriptor;
2629

2730
#[cfg(target_arch = "x86_64")]
2831
use linux_loader::loader::elf::Elf as Loader;
@@ -53,7 +56,6 @@ use linux_loader::loader::KernelLoader;
5356
use logger::{error, warn};
5457
use seccompiler::BpfThreadMap;
5558
use snapshot::Persist;
56-
use userfaultfd::Uffd;
5759
use utils::eventfd::EventFd;
5860
use utils::terminal::Terminal;
5961
use utils::time::TimestampUs;
@@ -66,6 +68,8 @@ use vm_superio::Rtc;
6668
pub enum StartMicrovmError {
6769
/// Unable to attach block device to Vmm.
6870
AttachBlockDevice(io::Error),
71+
/// Unable to create the memory backing file.
72+
BackingMemoryFile(io::Error),
6973
/// This error is thrown by the minimal boot loader implementation.
7074
ConfigureSystem(arch::Error),
7175
/// Internal errors are due to resource exhaustion.
@@ -119,6 +123,9 @@ impl Display for StartMicrovmError {
119123
AttachBlockDevice(err) => {
120124
write!(f, "Unable to attach block device to Vmm: {}", err)
121125
}
126+
BackingMemoryFile(err) => {
127+
write!(f, "Unable to create the memory backing file: {}", err)
128+
}
122129
ConfigureSystem(e) => write!(f, "System configuration error: {:?}", e),
123130
CreateRateLimiter(err) => write!(f, "Cannot create RateLimiter: {}", err),
124131
CreateNetDevice(err) => {
@@ -238,7 +245,7 @@ fn create_vmm_and_vcpus(
238245
instance_info: &InstanceInfo,
239246
event_manager: &mut EventManager,
240247
guest_memory: GuestMemoryMmap,
241-
uffd: Option<Uffd>,
248+
memory_descriptor: Option<MemoryDescriptor>,
242249
track_dirty_pages: bool,
243250
vcpu_count: u8,
244251
) -> std::result::Result<(Vmm, Vec<Vcpu>), StartMicrovmError> {
@@ -304,7 +311,7 @@ fn create_vmm_and_vcpus(
304311
shutdown_exit_code: None,
305312
vm,
306313
guest_memory,
307-
uffd,
314+
memory_descriptor,
308315
vcpus_handles: Vec::new(),
309316
vcpus_exit_evt,
310317
mmio_device_manager,
@@ -336,8 +343,23 @@ pub fn build_microvm_for_boot(
336343
let boot_config = vm_resources.boot_source().ok_or(MissingKernelConfig)?;
337344

338345
let track_dirty_pages = vm_resources.track_dirty_pages();
339-
let guest_memory =
340-
create_guest_memory(vm_resources.vm_config().mem_size_mib, track_dirty_pages)?;
346+
347+
let backing_memory_file = if let Some(ref file) = vm_resources.backing_memory_file {
348+
file.set_len((vm_resources.vm_config().mem_size_mib * 1024 * 1024) as u64)
349+
.map_err(|e| {
350+
error!("Failed to set backing memory file size: {}", e);
351+
StartMicrovmError::BackingMemoryFile(e)
352+
})?;
353+
354+
Some(file.clone())
355+
} else {
356+
None
357+
};
358+
let guest_memory = create_guest_memory(
359+
vm_resources.vm_config().mem_size_mib,
360+
backing_memory_file.clone(),
361+
track_dirty_pages,
362+
)?;
341363
let vcpu_config = vm_resources.vcpu_config();
342364
let entry_addr = load_kernel(boot_config, &guest_memory)?;
343365
let initrd = load_initrd_from_config(boot_config, &guest_memory)?;
@@ -369,7 +391,7 @@ pub fn build_microvm_for_boot(
369391
instance_info,
370392
event_manager,
371393
guest_memory,
372-
None,
394+
backing_memory_file.map(MemoryDescriptor::File),
373395
track_dirty_pages,
374396
vcpu_config.vcpu_count,
375397
)?;
@@ -458,7 +480,7 @@ pub fn build_microvm_from_snapshot(
458480
event_manager: &mut EventManager,
459481
microvm_state: MicrovmState,
460482
guest_memory: GuestMemoryMmap,
461-
uffd: Option<Uffd>,
483+
memory_descriptor: Option<MemoryDescriptor>,
462484
track_dirty_pages: bool,
463485
seccomp_filters: &BpfThreadMap,
464486
vm_resources: &mut VmResources,
@@ -473,7 +495,7 @@ pub fn build_microvm_from_snapshot(
473495
instance_info,
474496
event_manager,
475497
guest_memory.clone(),
476-
uffd,
498+
memory_descriptor,
477499
track_dirty_pages,
478500
vcpu_count,
479501
)?;
@@ -590,15 +612,24 @@ pub fn build_microvm_from_snapshot(
590612
/// Creates GuestMemory of `mem_size_mib` MiB in size.
591613
pub fn create_guest_memory(
592614
mem_size_mib: usize,
615+
backing_memory_file: Option<Arc<File>>,
593616
track_dirty_pages: bool,
594617
) -> std::result::Result<GuestMemoryMmap, StartMicrovmError> {
595618
let mem_size = mem_size_mib << 20;
596619
let arch_mem_regions = arch::arch_memory_regions(mem_size);
597620

621+
let mut offset = 0_u64;
598622
vm_memory::create_guest_memory(
599623
&arch_mem_regions
600624
.iter()
601-
.map(|(addr, size)| (None, *addr, *size))
625+
.map(|(addr, size)| {
626+
let file_offset = backing_memory_file
627+
.clone()
628+
.map(|file| FileOffset::from_arc(file, offset));
629+
offset += *size as u64;
630+
631+
(file_offset, *addr, *size)
632+
})
602633
.collect::<Vec<_>>()[..],
603634
track_dirty_pages,
604635
)
@@ -1076,7 +1107,7 @@ pub mod tests {
10761107
}
10771108

10781109
pub(crate) fn default_vmm() -> Vmm {
1079-
let guest_memory = create_guest_memory(128, false).unwrap();
1110+
let guest_memory = create_guest_memory(128, None, false).unwrap();
10801111

10811112
let vcpus_exit_evt = EventFd::new(libc::EFD_NONBLOCK)
10821113
.map_err(Error::EventFd)
@@ -1104,12 +1135,12 @@ pub mod tests {
11041135
shutdown_exit_code: None,
11051136
vm,
11061137
guest_memory,
1107-
uffd: None,
11081138
vcpus_handles: Vec::new(),
11091139
vcpus_exit_evt,
11101140
mmio_device_manager,
11111141
#[cfg(target_arch = "x86_64")]
11121142
pio_device_manager,
1143+
memory_descriptor: None,
11131144
}
11141145
}
11151146

@@ -1291,21 +1322,21 @@ pub mod tests {
12911322

12921323
// Case 1: create guest memory without dirty page tracking
12931324
{
1294-
let guest_memory = create_guest_memory(mem_size, false).unwrap();
1325+
let guest_memory = create_guest_memory(mem_size, None, false).unwrap();
12951326
assert!(!is_dirty_tracking_enabled(&guest_memory));
12961327
}
12971328

12981329
// Case 2: create guest memory with dirty page tracking
12991330
{
1300-
let guest_memory = create_guest_memory(mem_size, true).unwrap();
1331+
let guest_memory = create_guest_memory(mem_size, None, true).unwrap();
13011332
assert!(is_dirty_tracking_enabled(&guest_memory));
13021333
}
13031334
}
13041335

13051336
#[test]
13061337
fn test_create_vcpus() {
13071338
let vcpu_count = 2;
1308-
let guest_memory = create_guest_memory(128, false).unwrap();
1339+
let guest_memory = create_guest_memory(128, None, false).unwrap();
13091340

13101341
#[allow(unused_mut)]
13111342
let mut vm = setup_kvm_vm(&guest_memory, false).unwrap();

0 commit comments

Comments
 (0)