vmm: Add fallback handling for sending live migration

This patch adds a fallback path for sending live migration, where it
ensures the following behavior of source VM post live-migration:

1. The source VM will be paused only when the migration is completed
successfully, or otherwise it will keep running;

2. The source VM will always stop dirty pages logging.

Fixes: #2895

Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
Bo Chen 2021-08-02 11:23:48 -07:00 committed by Rob Bradford
parent eabcbb5159
commit 902fe20d41

View File

@ -999,6 +999,7 @@ impl Vmm {
send_data_migration.destination_url send_data_migration.destination_url
); );
if let Some(ref mut vm) = self.vm { if let Some(ref mut vm) = self.vm {
match {
let path = Self::socket_url_to_path(&send_data_migration.destination_url)?; let path = Self::socket_url_to_path(&send_data_migration.destination_url)?;
let mut socket = UnixStream::connect(&path).map_err(|e| { let mut socket = UnixStream::connect(&path).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e)) MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e))
@ -1101,9 +1102,6 @@ impl Vmm {
// Send last batch of dirty pages // Send last batch of dirty pages
Self::vm_maybe_send_dirty_pages(vm, &mut socket)?; Self::vm_maybe_send_dirty_pages(vm, &mut socket)?;
// Stop logging dirty pages
vm.stop_memory_dirty_log()?;
// Capture snapshot and send it // Capture snapshot and send it
let vm_snapshot = vm.snapshot()?; let vm_snapshot = vm.snapshot()?;
let snapshot_data = serde_json::to_vec(&vm_snapshot).unwrap(); let snapshot_data = serde_json::to_vec(&vm_snapshot).unwrap();
@ -1134,6 +1132,28 @@ impl Vmm {
} }
info!("Migration complete"); info!("Migration complete");
Ok(()) Ok(())
} {
// Stop logging dirty pages and keep the source VM paused unpon successful migration
Ok(()) => {
// Stop logging dirty pages
vm.stop_memory_dirty_log()?;
Ok(())
}
// Ensure the source VM continue to run upon unsuccessful migration
Err(e) => {
error!("Migration failed: {:?}", e);
// Stop logging dirty pages
vm.stop_memory_dirty_log()?;
if vm.get_state().unwrap() == VmState::Paused {
vm.resume()?;
}
e
}
}
} else { } else {
Err(MigratableError::MigrateSend(anyhow!("VM is not running"))) Err(MigratableError::MigrateSend(anyhow!("VM is not running")))
} }