mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: extract receive_memory_regions from memory manager
The memory manager is guarded by a mutex, thus parallel accesses to it and its members are not possible. But we have to execute this function in parallel when we introduce multiple TCP connections. Otherwise, the workers who receive the data and write it into guest memory will block on each other, and thus slow down the migration. Also rename the function to receive_memory_ranges 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:
@@ -36,7 +36,6 @@ use serde::{Deserialize, Serialize};
|
||||
use signal_hook::iterator::{Handle, Signals};
|
||||
use thiserror::Error;
|
||||
use tracer::trace_scoped;
|
||||
use vm_memory::ReadVolatile;
|
||||
use vm_memory::bitmap::AtomicBitmap;
|
||||
use vm_migration::protocol::*;
|
||||
use vm_migration::{
|
||||
@@ -1056,21 +1055,16 @@ impl Vmm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_receive_memory<T>(
|
||||
fn vm_receive_memory(
|
||||
&mut self,
|
||||
req: &Request,
|
||||
socket: &mut T,
|
||||
socket: &mut SocketStream,
|
||||
memory_manager: &mut MemoryManager,
|
||||
) -> std::result::Result<(), MigratableError>
|
||||
where
|
||||
T: Read + ReadVolatile,
|
||||
{
|
||||
// Read table
|
||||
) -> std::result::Result<(), MigratableError> {
|
||||
let table = MemoryRangeTable::read_from(socket, req.length())?;
|
||||
|
||||
// And then read the memory itself
|
||||
memory_manager.receive_memory_regions(&table, socket)?;
|
||||
Ok(())
|
||||
// And then the memory itself
|
||||
migration_transport::receive_memory_ranges(&memory_manager.guest_memory(), &table, socket)
|
||||
}
|
||||
|
||||
/// Performs the initial memory transmission (iteration zero) plus a
|
||||
|
||||
@@ -39,7 +39,7 @@ use vm_memory::guest_memory::{Error as MmapError, FileOffset};
|
||||
use vm_memory::mmap::MmapRegionError;
|
||||
use vm_memory::{
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryError, GuestMemoryRegion, GuestUsize, MmapRegion, ReadVolatile,
|
||||
GuestMemoryError, GuestMemoryRegion, GuestUsize, MmapRegion,
|
||||
};
|
||||
use vm_migration::protocol::{MemoryRange, MemoryRangeTable};
|
||||
use vm_migration::{
|
||||
@@ -2572,47 +2572,6 @@ impl MemoryManager {
|
||||
debug!("coredump total bytes {total_bytes}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn receive_memory_regions<F>(
|
||||
&mut self,
|
||||
ranges: &MemoryRangeTable,
|
||||
fd: &mut F,
|
||||
) -> std::result::Result<(), MigratableError>
|
||||
where
|
||||
F: ReadVolatile,
|
||||
{
|
||||
let guest_memory = self.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 read_exact_from() 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_read = mem
|
||||
.read_volatile_from(
|
||||
GuestAddress(range.gpa + offset),
|
||||
fd,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error receiving memory from socket: {e}"
|
||||
))
|
||||
})?;
|
||||
offset += bytes_read as u64;
|
||||
|
||||
if offset == range.length {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct MemoryNotify {
|
||||
|
||||
@@ -278,3 +278,41 @@ pub(crate) fn send_memory_ranges(
|
||||
MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
|
||||
)
|
||||
}
|
||||
|
||||
/// Receive memory contents for the given range table into guest memory.
|
||||
pub(crate) fn receive_memory_ranges(
|
||||
guest_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
ranges: &MemoryRangeTable,
|
||||
socket: &mut SocketStream,
|
||||
) -> Result<(), MigratableError> {
|
||||
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 read_exact_from() 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_read = mem
|
||||
.read_volatile_from(
|
||||
GuestAddress(range.gpa + offset),
|
||||
socket,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error receiving memory from socket: {e}"
|
||||
))
|
||||
})?;
|
||||
offset += bytes_read as u64;
|
||||
|
||||
if offset == range.length {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user