mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: extract send_memory_regions from vm
And rename it for better naming consistency. On-behalf-of: SAP sebastian.eydam@sap.com Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
This commit is contained in:
+2
-2
@@ -1187,7 +1187,7 @@ impl Vmm {
|
|||||||
|
|
||||||
// Send the current dirty pages
|
// Send the current dirty pages
|
||||||
let transfer_begin = Instant::now();
|
let transfer_begin = Instant::now();
|
||||||
migration_transport::vm_send_dirty_pages(vm, socket, &iteration_table)?;
|
migration_transport::send_memory_ranges(&vm.guest_memory(), &iteration_table, socket)?;
|
||||||
let transfer_duration = transfer_begin.elapsed();
|
let transfer_duration = transfer_begin.elapsed();
|
||||||
ctx.update_metrics_after_transfer(transfer_begin, transfer_duration);
|
ctx.update_metrics_after_transfer(transfer_begin, transfer_duration);
|
||||||
|
|
||||||
@@ -1329,7 +1329,7 @@ impl Vmm {
|
|||||||
|
|
||||||
ctx.update_metrics_before_transfer(iteration_begin, &final_table);
|
ctx.update_metrics_before_transfer(iteration_begin, &final_table);
|
||||||
let transfer_begin = Instant::now();
|
let transfer_begin = Instant::now();
|
||||||
migration_transport::vm_send_dirty_pages(vm, socket, &final_table)?;
|
migration_transport::send_memory_ranges(&vm.guest_memory(), &final_table, socket)?;
|
||||||
let transfer_duration = transfer_begin.elapsed();
|
let transfer_duration = transfer_begin.elapsed();
|
||||||
ctx.update_metrics_after_transfer(transfer_begin, transfer_duration);
|
ctx.update_metrics_after_transfer(transfer_begin, transfer_duration);
|
||||||
ctx.iteration += 1;
|
ctx.iteration += 1;
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ use std::result::Result;
|
|||||||
use anyhow::{Context, anyhow};
|
use anyhow::{Context, anyhow};
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
|
||||||
use vm_migration::protocol::{MemoryRangeTable, Request, Response};
|
use vm_migration::protocol::{MemoryRangeTable, Request, Response};
|
||||||
use vm_migration::{MigratableError, Snapshot};
|
use vm_migration::{MigratableError, Snapshot};
|
||||||
|
|
||||||
use crate::vm::Vm;
|
use crate::{GuestMemoryMmap, SocketStream, VmMigrationConfig};
|
||||||
use crate::{SocketStream, VmMigrationConfig};
|
|
||||||
|
|
||||||
/// Extract a UNIX socket path from a "unix:" migration URL.
|
/// Extract a UNIX socket path from a "unix:" migration URL.
|
||||||
fn socket_url_to_path(url: &str) -> Result<PathBuf, anyhow::Error> {
|
fn socket_url_to_path(url: &str) -> Result<PathBuf, anyhow::Error> {
|
||||||
@@ -137,29 +137,55 @@ pub(crate) fn send_state(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transmits the given [`MemoryRangeTable`] over the wire if there is at
|
/// Transmits the given [`MemoryRangeTable`] and the corresponding guest memory
|
||||||
/// least one region.
|
/// content over the wire if there is at least one range.
|
||||||
///
|
///
|
||||||
/// Sends a memory migration request, the range table, and the corresponding
|
/// Sends a memory migration request, the range table, and the corresponding
|
||||||
/// guest memory regions over the given socket. Waits for acknowledgment
|
/// guest memory range over the given socket. Waits for acknowledgment
|
||||||
/// from the destination.
|
/// from the destination.
|
||||||
pub(crate) fn vm_send_dirty_pages(
|
pub(crate) fn send_memory_ranges(
|
||||||
vm: &mut Vm,
|
guest_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
|
ranges: &MemoryRangeTable,
|
||||||
socket: &mut SocketStream,
|
socket: &mut SocketStream,
|
||||||
table: &MemoryRangeTable,
|
|
||||||
) -> Result<(), MigratableError> {
|
) -> Result<(), MigratableError> {
|
||||||
if table.regions().is_empty() {
|
if ranges.regions().is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Request::memory(table.length()).write_to(socket)?;
|
// Send the memory table
|
||||||
table.write_to(socket)?;
|
Request::memory(ranges.length()).write_to(socket)?;
|
||||||
|
ranges.write_to(socket)?;
|
||||||
|
|
||||||
// And then the memory itself
|
// And then the memory itself
|
||||||
vm.send_memory_regions(table, socket)?;
|
let mem = guest_memory.memory();
|
||||||
|
for range in ranges.regions() {
|
||||||
|
let mut offset: u64 = 0;
|
||||||
|
// Here we are manually handling the retry in case we can't read the
|
||||||
|
// whole region at once because we can't use the implementation
|
||||||
|
// from vm-memory::GuestMemory of write_all_to() as it is not
|
||||||
|
// following the correct behavior. For more info about this issue
|
||||||
|
// see: https://github.com/rust-vmm/vm-memory/issues/174
|
||||||
|
loop {
|
||||||
|
let bytes_written = mem
|
||||||
|
.write_volatile_to(
|
||||||
|
GuestAddress(range.gpa + offset),
|
||||||
|
socket,
|
||||||
|
(range.length - offset) as usize,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
MigratableError::MigrateSend(anyhow!(
|
||||||
|
"Error transferring memory to socket: {e}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
offset += bytes_written as u64;
|
||||||
|
|
||||||
|
if offset == range.length {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
expect_ok_response(
|
expect_ok_response(
|
||||||
socket,
|
socket,
|
||||||
MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
|
MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
|
||||||
)?;
|
)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-44
@@ -68,7 +68,7 @@ use vm_device::Bus;
|
|||||||
use vm_memory::GuestMemory;
|
use vm_memory::GuestMemory;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use vm_memory::{Address, ByteValued, GuestMemoryRegion, ReadVolatile};
|
use vm_memory::{Address, ByteValued, GuestMemoryRegion, ReadVolatile};
|
||||||
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, WriteVolatile};
|
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
|
||||||
use vm_migration::protocol::{MemoryRangeTable, Request, Response};
|
use vm_migration::protocol::{MemoryRangeTable, Request, Response};
|
||||||
use vm_migration::{
|
use vm_migration::{
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, snapshot_from_id,
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, snapshot_from_id,
|
||||||
@@ -2853,49 +2853,6 @@ impl Vm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the contents of the given guest memory regions to the provided sink.
|
|
||||||
/// Used, for example, during VM live migration to transfer memory to a socket.
|
|
||||||
pub fn send_memory_regions<F>(
|
|
||||||
&mut self,
|
|
||||||
ranges: &MemoryRangeTable,
|
|
||||||
fd: &mut F,
|
|
||||||
) -> std::result::Result<(), MigratableError>
|
|
||||||
where
|
|
||||||
F: WriteVolatile,
|
|
||||||
{
|
|
||||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
|
||||||
let mem = guest_memory.memory();
|
|
||||||
|
|
||||||
for range in ranges.regions() {
|
|
||||||
let mut offset: u64 = 0;
|
|
||||||
// Here we are manually handling the retry in case we can't the
|
|
||||||
// whole region at once because we can't use the implementation
|
|
||||||
// from vm-memory::GuestMemory of write_all_to() as it is not
|
|
||||||
// following the correct behavior. For more info about this issue
|
|
||||||
// see: https://github.com/rust-vmm/vm-memory/issues/174
|
|
||||||
loop {
|
|
||||||
let bytes_written = mem
|
|
||||||
.write_volatile_to(
|
|
||||||
GuestAddress(range.gpa + offset),
|
|
||||||
fd,
|
|
||||||
(range.length - offset) as usize,
|
|
||||||
)
|
|
||||||
.map_err(|e| {
|
|
||||||
MigratableError::MigrateSend(anyhow!(
|
|
||||||
"Error transferring memory to socket: {e}"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
offset += bytes_written as u64;
|
|
||||||
|
|
||||||
if offset == range.length {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||||
self.memory_manager
|
self.memory_manager
|
||||||
.lock()
|
.lock()
|
||||||
@@ -2903,6 +2860,10 @@ impl Vm {
|
|||||||
.memory_range_table(false)
|
.memory_range_table(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn guest_memory(&self) -> GuestMemoryAtomic<GuestMemoryMmap> {
|
||||||
|
self.memory_manager.lock().unwrap().guest_memory()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn device_tree(&self) -> Arc<Mutex<DeviceTree>> {
|
pub fn device_tree(&self) -> Arc<Mutex<DeviceTree>> {
|
||||||
self.device_manager.lock().unwrap().device_tree()
|
self.device_manager.lock().unwrap().device_tree()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user