From 6712958f2369b07be65e0b92e540166e4e2e4f38 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 7 Apr 2020 13:33:18 +0200 Subject: [PATCH] vmm: memory: Add prefault option when creating region When CoW can be used, the VM restoration time is reduced, but the pages are not populated. This can lead to some slowness from the guest when accessing these pages. Depending on the use case, we might prefer a slower boot time for better performances from guest runtime. The way to achieve this is to prefault the pages in this case, using the MAP_POPULATE flag along with CoW. Signed-off-by: Sebastien Boeuf --- vmm/src/memory_manager.rs | 17 +++++++++++++---- vmm/src/vm.rs | 10 +++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 320abdc7c..544a50081 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -229,6 +229,7 @@ impl MemoryManager { fd: Arc, config: &MemoryConfig, ext_regions: Option>, + prefault: bool, ) -> Result>, Error> { // Init guest memory let arch_mem_regions = arch::arch_memory_regions(config.size); @@ -251,6 +252,7 @@ impl MemoryManager { region.start_addr, region.size as usize, true, + prefault, )?); } } else { @@ -260,6 +262,7 @@ impl MemoryManager { region.0, region.1, false, + prefault, )?); } } @@ -288,6 +291,7 @@ impl MemoryManager { start_addr, size as usize, false, + false, )?); virtiomem_resize = Some(vm_virtio::Resize::new().map_err(Error::EventFdFail)?); @@ -415,10 +419,10 @@ impl MemoryManager { // allows for a faster VM restoration and does not require us to // fill the memory content, hence we can return right away. if config.file.is_none() { - return MemoryManager::new(fd, config, Some(ext_regions)); + return MemoryManager::new(fd, config, Some(ext_regions), false); }; - let memory_manager = MemoryManager::new(fd, config, None)?; + let memory_manager = MemoryManager::new(fd, config, None, false)?; let guest_memory = memory_manager.lock().unwrap().guest_memory(); // In case the previous config was using a backing file, this means @@ -458,6 +462,7 @@ impl MemoryManager { start_addr: GuestAddress, size: usize, copy_on_write: bool, + prefault: bool, ) -> Result, Error> { Ok(Arc::new(match backing_file { Some(ref file) => { @@ -479,11 +484,14 @@ impl MemoryManager { f.set_len(size as u64).map_err(Error::SharedFileSetLen)?; - let mmap_flags = if copy_on_write { + let mut mmap_flags = if copy_on_write { libc::MAP_NORESERVE | libc::MAP_PRIVATE } else { libc::MAP_NORESERVE | libc::MAP_SHARED }; + if prefault { + mmap_flags |= libc::MAP_POPULATE; + } GuestRegionMmap::new( MmapRegion::build( Some(FileOffset::new(f, 0)), @@ -544,7 +552,8 @@ impl MemoryManager { } // Allocate memory for the region - let region = MemoryManager::create_ram_region(&self.backing_file, start_addr, size, false)?; + let region = + MemoryManager::create_ram_region(&self.backing_file, start_addr, size, false, false)?; // Map it into the guest self.create_userspace_mapping( diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 933de72c9..86d14701b 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -360,9 +360,13 @@ impl Vm { vmm_path: PathBuf, ) -> Result { let (kvm, fd) = Vm::kvm_new()?; - let memory_manager = - MemoryManager::new(fd.clone(), &config.lock().unwrap().memory.clone(), None) - .map_err(Error::MemoryManager)?; + let memory_manager = MemoryManager::new( + fd.clone(), + &config.lock().unwrap().memory.clone(), + None, + false, + ) + .map_err(Error::MemoryManager)?; Vm::new_from_memory_manager( config,