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

@@ -1049,6 +1049,9 @@ impl Vmm {
// Send last batch of dirty pages
Self::vm_maybe_send_dirty_pages(vm, &mut socket)?;
// Stop logging dirty pages
vm.stop_memory_dirty_log()?;
// Capture snapshot and send it
let vm_snapshot = vm.snapshot()?;
let snapshot_data = serde_json::to_vec(&vm_snapshot).unwrap();

View File

@@ -1561,14 +1561,22 @@ impl MemoryManager {
Ok(table)
}
// The dirty log is cleared by the kernel by calling the KVM_GET_DIRTY_LOG ioctl.
// Just before we do a bulk copy we want to clear the dirty log so that
// Start the dirty log on guest RAM in the hypervisor (kvm/mshv).
// Also, reset the dirty bitmap logged by the vmm.
// Just before we do a bulk copy we want to start/clear the dirty log so that
// pages touched during our bulk copy are tracked.
pub fn start_memory_dirty_log(&self) -> std::result::Result<(), MigratableError> {
for r in &self.guest_ram_mappings {
self.vm.get_dirty_log(r.slot, r.size).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error getting VM dirty log {}", e))
})?;
let user_addr = self
.guest_memory()
.memory()
.get_host_address(GuestAddress(r.gpa))
.unwrap();
self.vm
.start_dirty_log(r.slot, r.gpa, r.size, user_addr as u64)
.map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error starting VM dirty log {}", e))
})?;
}
for r in self.guest_memory.memory().iter() {
@@ -1577,6 +1585,23 @@ impl MemoryManager {
Ok(())
}
pub fn stop_memory_dirty_log(&self) -> std::result::Result<(), MigratableError> {
for r in &self.guest_ram_mappings {
let user_addr = self
.guest_memory()
.memory()
.get_host_address(GuestAddress(r.gpa))
.unwrap();
self.vm
.stop_dirty_log(r.slot, r.gpa, r.size, user_addr as u64)
.map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error stopping VM dirty log {}", e))
})?;
}
Ok(())
}
}
#[cfg(feature = "acpi")]

View File

@@ -2156,6 +2156,10 @@ impl Vm {
self.memory_manager.lock().unwrap().start_memory_dirty_log()
}
pub fn stop_memory_dirty_log(&self) -> std::result::Result<(), MigratableError> {
self.memory_manager.lock().unwrap().stop_memory_dirty_log()
}
pub fn dirty_memory_range_table(
&self,
) -> std::result::Result<MemoryRangeTable, MigratableError> {