hypervisor, vmm: Add dynamic control of logging dirty pages

This patch extends slightly the current live-migration code path with
the ability to dynamically start and stop logging dirty-pages, which
relies on two new methods added to the `hypervisor::vm::Vm` Trait. This
patch also contains a complete implementation of the two new methods
based on `kvm` and placeholders for `mshv` in the `hypervisor` crate.

Fixes: #2858

Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
Bo Chen
2021-07-21 19:16:30 -07:00
committed by Bo Chen
parent a33280b8ad
commit 5e0d498582
6 changed files with 144 additions and 5 deletions

View File

@@ -383,6 +383,59 @@ impl vm::Vm for KvmVm {
Ok(())
}
///
/// Start logging dirty pages
///
fn start_dirty_log(
&self,
slot: u32,
guest_phys_addr: u64,
memory_size: u64,
userspace_addr: u64,
) -> vm::Result<()> {
let region = self.make_user_memory_region(
slot,
guest_phys_addr,
memory_size,
userspace_addr,
false,
true,
);
// Safe because guest regions are guaranteed not to overlap.
unsafe {
self.fd
.set_user_memory_region(region)
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
}
}
///
/// Stop logging dirty pages
///
fn stop_dirty_log(
&self,
slot: u32,
guest_phys_addr: u64,
memory_size: u64,
userspace_addr: u64,
) -> vm::Result<()> {
let region = self.make_user_memory_region(
slot,
guest_phys_addr,
memory_size,
userspace_addr,
false,
false,
);
// Safe because guest regions are guaranteed not to overlap.
unsafe {
self.fd
.set_user_memory_region(region)
.map_err(|e| vm::HypervisorVmError::StopDirtyLog(e.into()))
}
}
///
/// Get dirty pages bitmap (one bit per page)
///

View File

@@ -877,6 +877,34 @@ impl vm::Vm for MshvVm {
Ok(())
}
///
/// Start logging dirty pages
///
fn start_dirty_log(
&self,
_slot: u32,
_guest_phys_addr: u64,
_memory_size: u64,
_userspace_addr: u64,
) -> vm::Result<()> {
Err(vm::HypervisorVmError::StartDirtyLog(anyhow!(
"functionality not implemented"
)))
}
///
/// Stop logging dirty pages
///
fn stop_dirty_log(
&self,
_slot: u32,
_guest_phys_addr: u64,
_memory_size: u64,
_userspace_addr: u64,
) -> vm::Result<()> {
Err(vm::HypervisorVmError::StopDirtyLog(anyhow!(
"functionality not implemented"
)))
}
///
/// Get dirty pages bitmap (one bit per page)
///
fn get_dirty_log(&self, _slot: u32, _memory_size: u64) -> vm::Result<Vec<u64>> {

View File

@@ -168,6 +168,16 @@ pub enum HypervisorVmError {
#[error("Failed to write to IO Bus: {0}")]
IoBusWrite(#[source] anyhow::Error),
///
/// Start dirty log error
///
#[error("Failed to get dirty log: {0}")]
StartDirtyLog(#[source] anyhow::Error),
///
/// Stop dirty log error
///
#[error("Failed to get dirty log: {0}")]
StopDirtyLog(#[source] anyhow::Error),
///
/// Get dirty log error
///
#[error("Failed to get dirty log: {0}")]
@@ -270,6 +280,22 @@ pub trait Vm: Send + Sync {
fn state(&self) -> Result<VmState>;
/// Set the VM state
fn set_state(&self, state: VmState) -> Result<()>;
/// Start logging dirty pages
fn start_dirty_log(
&self,
slot: u32,
guest_phys_addr: u64,
memory_size: u64,
userspace_addr: u64,
) -> Result<()>;
/// Stop logging dirty pages
fn stop_dirty_log(
&self,
slot: u32,
guest_phys_addr: u64,
memory_size: u64,
userspace_addr: u64,
) -> Result<()>;
/// Get dirty pages bitmap
fn get_dirty_log(&self, slot: u32, memory_size: u64) -> Result<Vec<u64>>;
#[cfg(feature = "tdx")]