vmm: memory_manager: Always copy anonymous RAM regions from disk

When restoring if a region of RAM is backed by anonymous memory i.e from
memfd_create() then copy the contents of the ram from the file that has
been saved to disk.

Previously the code would map the memory from that file into the guest
using a MAP_PRIVATE mapping. This has the effect of
minimising the restore time but provides an issue where the restored VM
does not have the same structure as the snapshotted VM, in particular
memory is backed by files in the restored VM that were anonymously
backed in the original.

This creates two problems:

* The snapshot data is mapped from files for the pages of the guest
  which prevents the storage from being reclaimed.
* When snapshotting again the guest memory will not be correctly saved
  as it will have looked like it was backed by a file so it will not be
  written to disk but as it is a MAP_PRIVATE mapping the changes will
  never be written to the disk again. This results in incorrect
  behaviour.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-10-22 15:33:34 +01:00 committed by Sebastien Boeuf
parent 255dbd29ef
commit a60b437f89

View File

@ -823,8 +823,8 @@ impl MemoryManager {
#[allow(clippy::too_many_arguments)]
fn create_ram_region(
file: &Option<PathBuf>,
mut file_offset: u64,
backing_file: &Option<PathBuf>,
file_offset: u64,
start_addr: GuestAddress,
size: usize,
prefault: bool,
@ -833,27 +833,12 @@ impl MemoryManager {
host_numa_node: Option<u32>,
ext_regions: &Option<Vec<MemoryRegion>>,
) -> Result<Arc<GuestRegionMmap>, Error> {
let mut backing_file: Option<PathBuf> = file.clone();
let mut copy_ext_region_content: Option<PathBuf> = None;
if let Some(ext_regions) = ext_regions {
for ext_region in ext_regions.iter() {
if ext_region.start_addr == start_addr && ext_region.size as usize == size {
if ext_region.backing_file.is_some() {
// If the region is memory mapped as "shared", then we
// don't replace the backing file, but expect to copy
// the content from the external backing file after the
// region has been created.
if shared {
copy_ext_region_content = ext_region.backing_file.clone();
} else {
backing_file = ext_region.backing_file.clone();
// We must override the file offset as in this case
// we're restoring an existing region, which means
// it will fit perfectly the calculated region.
file_offset = 0;
}
}
copy_ext_region_content = ext_region.backing_file.clone();
// No need to iterate further as we found the external
// region matching the current region.