mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Add support for resuming automatically on restore
Add an option that can be used when restoring to resume the VM. This is particularly useful when restoring the VM via the direct VMM command line, when you might not want/have an API socket configured. Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
@@ -2603,17 +2603,20 @@ pub struct RestoreConfig {
|
||||
pub memory_restore_mode: MemoryRestoreMode,
|
||||
#[serde(default)]
|
||||
pub net_fds: Option<Vec<RestoredNetConfig>>,
|
||||
#[serde(default)]
|
||||
pub resume: bool,
|
||||
}
|
||||
|
||||
impl RestoreConfig {
|
||||
pub const SYNTAX: &'static str = "Restore from a VM snapshot. \
|
||||
\nRestore parameters \"source_url=<source_url>,prefault=on|off,memory_restore_mode=copy|ondemand,\
|
||||
net_fds=<list_of_net_ids_with_their_associated_fds>\" \
|
||||
net_fds=<list_of_net_ids_with_their_associated_fds>,resume=true|false\" \
|
||||
\n`source_url` should be a valid URL (e.g file:///foo/bar or tcp://192.168.1.10/foo) \
|
||||
\n`prefault` controls eager prefaulting for the copy-based restore path (disabled by default) \
|
||||
\n`memory_restore_mode=copy` preserves the existing eager read-copy restore behavior, while `memory_restore_mode=ondemand` enables lazy demand paging and fails restore if userfaultfd support is unavailable \
|
||||
\n`net_fds` is a list of net ids with new file descriptors. \
|
||||
Only net devices backed by FDs directly are needed as input.";
|
||||
Only net devices backed by FDs directly are needed as input.\
|
||||
\n `resume` controls whether the VM will be directly resumed after restore ";
|
||||
|
||||
pub fn parse(restore: &str) -> Result<Self> {
|
||||
let mut parser = OptionParser::new();
|
||||
@@ -2621,7 +2624,8 @@ impl RestoreConfig {
|
||||
.add("source_url")
|
||||
.add("prefault")
|
||||
.add("memory_restore_mode")
|
||||
.add("net_fds");
|
||||
.add("net_fds")
|
||||
.add("resume");
|
||||
parser.parse(restore).map_err(Error::ParseRestore)?;
|
||||
|
||||
let source_url = parser
|
||||
@@ -2649,12 +2653,18 @@ impl RestoreConfig {
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
let resume = parser
|
||||
.convert::<Toggle>("resume")
|
||||
.map_err(Error::ParseRestore)?
|
||||
.unwrap_or(Toggle(false))
|
||||
.0;
|
||||
|
||||
Ok(RestoreConfig {
|
||||
source_url,
|
||||
prefault,
|
||||
memory_restore_mode,
|
||||
net_fds,
|
||||
resume,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4546,6 +4556,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
prefault: false,
|
||||
memory_restore_mode: MemoryRestoreMode::Copy,
|
||||
net_fds: None,
|
||||
resume: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -4568,6 +4579,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
fds: Some(vec![5, 6, 7, 8]),
|
||||
}
|
||||
]),
|
||||
resume: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -4577,6 +4589,17 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
prefault: false,
|
||||
memory_restore_mode: MemoryRestoreMode::OnDemand,
|
||||
net_fds: None,
|
||||
resume: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
RestoreConfig::parse("source_url=/path/to/snapshot,resume=on")?,
|
||||
RestoreConfig {
|
||||
source_url: PathBuf::from("/path/to/snapshot"),
|
||||
prefault: false,
|
||||
memory_restore_mode: MemoryRestoreMode::Copy,
|
||||
net_fds: None,
|
||||
resume: true,
|
||||
}
|
||||
);
|
||||
// Parsing should fail as source_url is a required field
|
||||
@@ -4678,6 +4701,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
fds: Some(vec![7, 8]),
|
||||
},
|
||||
]),
|
||||
resume: false,
|
||||
};
|
||||
valid_config.validate(&snapshot_vm_config).unwrap();
|
||||
|
||||
@@ -4742,6 +4766,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
prefault: false,
|
||||
memory_restore_mode: MemoryRestoreMode::Copy,
|
||||
net_fds: None,
|
||||
resume: false,
|
||||
};
|
||||
snapshot_vm_config.net = Some(vec![NetConfig {
|
||||
id: Some("net2".to_owned()),
|
||||
@@ -4755,6 +4780,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
||||
prefault: true,
|
||||
memory_restore_mode: MemoryRestoreMode::OnDemand,
|
||||
net_fds: None,
|
||||
resume: false,
|
||||
};
|
||||
assert_eq!(
|
||||
invalid_restore_mode.validate(&snapshot_vm_config),
|
||||
|
||||
@@ -1849,16 +1849,22 @@ impl RequestHandler for Vmm {
|
||||
restore_cfg.prefault,
|
||||
restore_cfg.memory_restore_mode,
|
||||
)
|
||||
.map_err(|vm_restore_err| {
|
||||
error!("VM Restore failed: {vm_restore_err:?}");
|
||||
|
||||
// Cleanup the VM being created while vm restore
|
||||
.and_then(|()| {
|
||||
if restore_cfg.resume {
|
||||
self.vm_resume()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.map_err(|e| {
|
||||
error!("VM Restore failed: {e:?}");
|
||||
if let Err(e) = self.vm_delete() {
|
||||
return e;
|
||||
}
|
||||
e
|
||||
})?;
|
||||
|
||||
vm_restore_err
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
|
||||
Reference in New Issue
Block a user