mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Add support for sending and receiving migration if VM is paused
This is tested by: Source VMM: target/debug/cloud-hypervisor --kernel ~/src/linux/vmlinux \ --pmem file=~/workloads/focal.raw --cpus boot=1 \ --memory size=2048M \ --cmdline"root=/dev/pmem0p1 console=ttyS0" --serial tty --console off \ --api-socket=/tmp/api1 -v Destination VMM: target/debug/cloud-hypervisor --api-socket=/tmp/api2 -v And the following commands: target/debug/ch-remote --api-socket=/tmp/api1 pause target/debug/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/foo & target/debug/ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/foo target/debug/ch-remote --api-socket=/tmp/api2 resume The VM is then responsive on the destination VMM. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
committed by
Samuel Ortiz
parent
dfe2dadb3e
commit
ca60adda70
@@ -58,7 +58,7 @@ use std::ffi::CString;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::fmt;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, Write};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Deref;
|
||||
@@ -67,10 +67,11 @@ use std::{result, str, thread};
|
||||
use url::Url;
|
||||
use vm_device::Bus;
|
||||
use vm_memory::{
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap,
|
||||
GuestRegionMmap,
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryMmap, GuestMemoryRegion, GuestRegionMmap,
|
||||
};
|
||||
use vm_migration::{
|
||||
protocol::{MemoryRange, MemoryRangeTable},
|
||||
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
|
||||
Transportable,
|
||||
};
|
||||
@@ -1607,6 +1608,68 @@ impl Vm {
|
||||
pub fn balloon_size(&self) -> u64 {
|
||||
self.device_manager.lock().unwrap().balloon_size()
|
||||
}
|
||||
|
||||
pub fn receive_memory_regions<F>(
|
||||
&mut self,
|
||||
ranges: &MemoryRangeTable,
|
||||
fd: &mut F,
|
||||
) -> std::result::Result<(), MigratableError>
|
||||
where
|
||||
F: Read,
|
||||
{
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
let mem = guest_memory.memory();
|
||||
|
||||
for range in ranges.regions() {
|
||||
mem.read_exact_from(GuestAddress(range.gpa), fd, range.length as usize)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error transferring memory to socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_memory_regions<F>(
|
||||
&mut self,
|
||||
ranges: &MemoryRangeTable,
|
||||
fd: &mut F,
|
||||
) -> std::result::Result<(), MigratableError>
|
||||
where
|
||||
F: Write,
|
||||
{
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
let mem = guest_memory.memory();
|
||||
|
||||
for range in ranges.regions() {
|
||||
mem.write_all_to(GuestAddress(range.gpa), fd, range.length as usize)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!(
|
||||
"Error transferring memory to socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
|
||||
guest_memory.memory().with_regions_mut(|_, region| {
|
||||
table.push(MemoryRange {
|
||||
gpa: region.start_addr().raw_value(),
|
||||
length: region.len() as u64,
|
||||
});
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for Vm {
|
||||
|
||||
Reference in New Issue
Block a user