Skip to content

Commit

Permalink
vmm: Fix migration when writing/reading big chunks of data
Browse files Browse the repository at this point in the history
Both read_exact_from() and write_all_to() functions from the GuestMemory
trait implementation in vm-memory are buggy. They should retry until
they wrote or read the amount of data that was expected, but instead
they simply return an error when this happens. This causes the migration
to fail when trying to send important amount of data through the
migration socket, due to large memory regions.

This should be eventually fixed in vm-memory, and here is the link to
follow up on the issue: rust-vmm/vm-memory#174

Signed-off-by: Sebastien Boeuf <[email protected]>
  • Loading branch information
Sebastien Boeuf committed Sep 27, 2021
1 parent cb59976 commit da97975
Showing 1 changed file with 51 additions and 14 deletions.
65 changes: 51 additions & 14 deletions vmm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2115,14 +2115,33 @@ impl Vm {
let mem = guest_memory.memory();

for range in ranges.regions() {
mem.read_exact_from(GuestAddress(range.gpa), fd, range.length as usize)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error transferring memory to socket: {}",
e
))
})?;
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_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(())
}

Expand All @@ -2138,13 +2157,31 @@ impl Vm {
let mem = guest_memory.memory();

for range in ranges.regions() {
mem.write_all_to(GuestAddress(range.gpa), fd, range.length as usize)
.map_err(|e| {
MigratableError::MigrateSend(anyhow!(
"Error transferring memory to socket: {}",
e
))
})?;
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_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(())
Expand Down

0 comments on commit da97975

Please sign in to comment.