vmm: memory_manager: Implement the Transportable trait

This implements the send() function of the Transportable trait, so that
the guest memory regions can be saved into one file per region.

This will need to be extended for live migration, as it will require
other transport methods and the recv() function will need to be
implemented too.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2020-02-25 02:38:08 +01:00 committed by Sebastien Boeuf
parent e606112cef
commit 20ba271b6c
3 changed files with 119 additions and 2 deletions

53
Cargo.lock generated
View File

@ -436,6 +436,17 @@ dependencies = [
"libc",
]
[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "ipnetwork"
version = "0.15.1"
@ -554,6 +565,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memchr"
version = "2.3.3"
@ -649,6 +666,12 @@ dependencies = [
"vm-memory",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-utils"
version = "0.1.0-alpha.4"
@ -1211,6 +1234,24 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
dependencies = [
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
dependencies = [
"smallvec",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
@ -1229,6 +1270,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "url"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
dependencies = [
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "utf8-ranges"
version = "1.0.4"
@ -1448,6 +1500,7 @@ dependencies = [
"serde_json",
"signal-hook",
"tempfile",
"url",
"vfio",
"vm-allocator",
"vm-device",

View File

@ -32,6 +32,7 @@ seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v
serde = {version = ">=1.0.27", features = ["rc"] }
serde_derive = ">=1.0.27"
serde_json = ">=1.0.9"
url = "2.1.1"
vfio = { path = "../vfio", optional = true }
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }

View File

@ -17,10 +17,11 @@ use std::io;
use std::os::unix::io::FromRawFd;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use url::Url;
use vm_allocator::{GsiApic, SystemAllocator};
use vm_memory::guest_memory::FileOffset;
use vm_memory::{
mmap::MmapRegionError, Address, Error as MmapError, GuestAddress, GuestAddressSpace,
mmap::MmapRegionError, Address, Bytes, Error as MmapError, GuestAddress, GuestAddressSpace,
GuestMemory, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap, GuestMemoryRegion,
GuestRegionMmap, GuestUsize, MmapRegion,
};
@ -971,5 +972,67 @@ impl Snapshottable for MemoryManager {
}
}
impl Transportable for MemoryManager {}
impl Transportable for MemoryManager {
fn send(
&self,
_snapshot: &Snapshot,
destination_url: &str,
) -> std::result::Result<(), MigratableError> {
let url = Url::parse(destination_url).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Could not parse destination URL: {}", e))
})?;
match url.scheme() {
"file" => {
let vm_memory_snapshot_path = url
.to_file_path()
.map_err(|_| {
MigratableError::MigrateSend(anyhow!(
"Could not convert file URL to a file path"
))
})
.and_then(|path| {
if !path.is_dir() {
return Err(MigratableError::MigrateSend(anyhow!(
"Destination is not a directory"
)));
}
Ok(path)
})?;
if let Some(guest_memory) = &*self.snapshot.lock().unwrap() {
guest_memory.with_regions_mut(|index, region| {
let mut memory_region_path = vm_memory_snapshot_path.clone();
memory_region_path.push(format!("memory-region-{}", index));
// Create the snapshot file for the region
let mut memory_region_file = OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(memory_region_path)
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
guest_memory
.write_to(
region.start_addr(),
&mut memory_region_file,
region.len().try_into().unwrap(),
)
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
Ok(())
})?;
}
}
_ => {
return Err(MigratableError::MigrateSend(anyhow!(
"Unsupported VM transport URL scheme: {}",
url.scheme()
)))
}
}
Ok(())
}
}
impl Migratable for MemoryManager {}