vmm: Simplify snapshot/restore path handling

Extend the existing url_to_path() to take the URL string and then use
that to simplify the snapshot/restore code paths.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-03-12 10:46:36 +00:00 committed by Sebastien Boeuf
parent ebcbab739e
commit cc78a597cd
3 changed files with 50 additions and 88 deletions

View File

@ -6,6 +6,7 @@ extern crate hypervisor;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::config::SgxEpcConfig; use crate::config::SgxEpcConfig;
use crate::config::{HotplugMethod, MemoryConfig, MemoryZoneConfig}; use crate::config::{HotplugMethod, MemoryConfig, MemoryZoneConfig};
use crate::migration::url_to_path;
use crate::MEMORY_MANAGER_SNAPSHOT_ID; use crate::MEMORY_MANAGER_SNAPSHOT_ID;
#[cfg(feature = "acpi")] #[cfg(feature = "acpi")]
use acpi_tables::{aml, aml::Aml}; use acpi_tables::{aml, aml::Aml};
@ -851,9 +852,7 @@ impl MemoryManager {
)?; )?;
if let Some(source_url) = source_url { if let Some(source_url) = source_url {
let url = Url::parse(source_url).unwrap(); let vm_snapshot_path = url_to_path(source_url).map_err(Error::Restore)?;
/* url must be valid dir which is verified in recv_vm_snapshot() */
let vm_snapshot_path = url.to_file_path().unwrap();
if let Some(mem_section) = snapshot if let Some(mem_section) = snapshot
.snapshot_data .snapshot_data

View File

@ -7,61 +7,40 @@ use anyhow::anyhow;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::path::PathBuf; use std::path::PathBuf;
use url::Url;
use vm_migration::{MigratableError, Snapshot}; use vm_migration::{MigratableError, Snapshot};
pub const VM_SNAPSHOT_FILE: &str = "vm.json"; pub const VM_SNAPSHOT_FILE: &str = "vm.json";
pub fn url_to_path(url: &Url) -> std::result::Result<PathBuf, MigratableError> { pub fn url_to_path(url: &str) -> std::result::Result<PathBuf, MigratableError> {
match url.scheme() { let path: PathBuf = url
"file" => url .strip_prefix("file://")
.to_file_path() .ok_or_else(|| {
.map_err(|_| { MigratableError::MigrateSend(anyhow!("Could not extract path from URL: {}", url))
MigratableError::MigrateSend(anyhow!( })
"Could not convert file URL to a file path: {}", .map(|s| s.into())?;
url.as_str()
))
})
.and_then(|path| {
if !path.is_dir() {
return Err(MigratableError::MigrateSend(anyhow!(
"Destination is not a directory"
)));
}
Ok(path)
}),
_ => Err(MigratableError::MigrateSend(anyhow!( if !path.is_dir() {
"URL scheme is not file: {}", return Err(MigratableError::MigrateSend(anyhow!(
url.scheme() "Destination is not a directory"
))), )));
} }
Ok(path)
} }
pub fn recv_vm_snapshot(source_url: &str) -> std::result::Result<Snapshot, MigratableError> { pub fn recv_vm_snapshot(source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
let url = Url::parse(source_url).map_err(|e| { let mut vm_snapshot_path = url_to_path(source_url)?;
MigratableError::MigrateSend(anyhow!("Could not parse destination URL: {}", e))
})?;
match url.scheme() { vm_snapshot_path.push(VM_SNAPSHOT_FILE);
"file" => {
let mut vm_snapshot_path = url_to_path(&url)?;
vm_snapshot_path.push(VM_SNAPSHOT_FILE);
// Try opening the snapshot file // Try opening the snapshot file
let vm_snapshot_file = let vm_snapshot_file =
File::open(vm_snapshot_path).map_err(|e| MigratableError::MigrateSend(e.into()))?; File::open(vm_snapshot_path).map_err(|e| MigratableError::MigrateSend(e.into()))?;
let vm_snapshot_reader = BufReader::new(vm_snapshot_file); let vm_snapshot_reader = BufReader::new(vm_snapshot_file);
let vm_snapshot = serde_json::from_reader(vm_snapshot_reader) let vm_snapshot = serde_json::from_reader(vm_snapshot_reader)
.map_err(|e| MigratableError::MigrateReceive(e.into()))?; .map_err(|e| MigratableError::MigrateReceive(e.into()))?;
Ok(vm_snapshot) Ok(vm_snapshot)
}
_ => Err(MigratableError::MigrateSend(anyhow!(
"Unsupported VM transport URL scheme: {}",
url.scheme()
))),
}
} }
pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> { pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> {

View File

@ -71,7 +71,6 @@ use std::num::Wrapping;
use std::ops::Deref; use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::{result, str, thread}; use std::{result, str, thread};
use url::Url;
use vm_device::Bus; use vm_device::Bus;
use vm_memory::{ use vm_memory::{
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
@ -2311,52 +2310,37 @@ impl Transportable for Vm {
snapshot: &Snapshot, snapshot: &Snapshot,
destination_url: &str, destination_url: &str,
) -> std::result::Result<(), MigratableError> { ) -> std::result::Result<(), MigratableError> {
let url = Url::parse(destination_url).map_err(|e| { let mut vm_snapshot_path = url_to_path(destination_url)?;
MigratableError::MigrateSend(anyhow!("Could not parse destination URL: {}", e)) vm_snapshot_path.push(VM_SNAPSHOT_FILE);
})?;
match url.scheme() { // Create the snapshot file
"file" => { let mut vm_snapshot_file = OpenOptions::new()
let mut vm_snapshot_path = url_to_path(&url)?; .read(true)
vm_snapshot_path.push(VM_SNAPSHOT_FILE); .write(true)
.create_new(true)
.open(vm_snapshot_path)
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
// Create the snapshot file // Serialize and write the snapshot
let mut vm_snapshot_file = OpenOptions::new() let vm_snapshot =
.read(true) serde_json::to_vec(snapshot).map_err(|e| MigratableError::MigrateSend(e.into()))?;
.write(true)
.create_new(true)
.open(vm_snapshot_path)
.map_err(|e| MigratableError::MigrateSend(e.into()))?;
// Serialize and write the snapshot vm_snapshot_file
let vm_snapshot = serde_json::to_vec(snapshot) .write(&vm_snapshot)
.map_err(|e| MigratableError::MigrateSend(e.into()))?; .map_err(|e| MigratableError::MigrateSend(e.into()))?;
vm_snapshot_file // Tell the memory manager to also send/write its own snapshot.
.write(&vm_snapshot) if let Some(memory_manager_snapshot) = snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID) {
.map_err(|e| MigratableError::MigrateSend(e.into()))?; self.memory_manager
.lock()
// Tell the memory manager to also send/write its own snapshot. .unwrap()
if let Some(memory_manager_snapshot) = .send(&*memory_manager_snapshot.clone(), destination_url)?;
snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID) } else {
{ return Err(MigratableError::Restore(anyhow!(
self.memory_manager "Missing memory manager snapshot"
.lock() )));
.unwrap()
.send(&*memory_manager_snapshot.clone(), destination_url)?;
} else {
return Err(MigratableError::Restore(anyhow!(
"Missing memory manager snapshot"
)));
}
}
_ => {
return Err(MigratableError::MigrateSend(anyhow!(
"Unsupported VM transport URL scheme: {}",
url.scheme()
)))
}
} }
Ok(()) Ok(())
} }
} }