@@ -12,9 +12,11 @@ use libc::EFD_NONBLOCK;
1212use logger:: METRICS ;
1313use std:: convert:: TryFrom ;
1414use std:: fmt:: { Display , Formatter } ;
15+ use std:: fs:: File ;
1516use std:: io:: { self , Read , Seek , SeekFrom } ;
1617use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
1718use std:: sync:: { Arc , Mutex } ;
19+ use vm_memory:: FileOffset ;
1820use vm_superio:: Serial ;
1921
2022#[ cfg( target_arch = "aarch64" ) ]
@@ -23,6 +25,7 @@ use crate::construct_kvm_mpidrs;
2325use crate :: device_manager:: legacy:: PortIODeviceManager ;
2426use crate :: device_manager:: mmio:: MMIODeviceManager ;
2527use crate :: device_manager:: persist:: MMIODevManagerConstructorArgs ;
28+ use crate :: persist:: MemoryDescriptor ;
2629
2730#[ cfg( target_arch = "x86_64" ) ]
2831use linux_loader:: loader:: elf:: Elf as Loader ;
@@ -53,7 +56,6 @@ use linux_loader::loader::KernelLoader;
5356use logger:: { error, warn} ;
5457use seccompiler:: BpfThreadMap ;
5558use snapshot:: Persist ;
56- use userfaultfd:: Uffd ;
5759use utils:: eventfd:: EventFd ;
5860use utils:: terminal:: Terminal ;
5961use utils:: time:: TimestampUs ;
@@ -66,6 +68,8 @@ use vm_superio::Rtc;
6668pub enum StartMicrovmError {
6769 /// Unable to attach block device to Vmm.
6870 AttachBlockDevice ( io:: Error ) ,
71+ /// Unable to create the memory backing file.
72+ BackingMemoryFile ( io:: Error ) ,
6973 /// This error is thrown by the minimal boot loader implementation.
7074 ConfigureSystem ( arch:: Error ) ,
7175 /// Internal errors are due to resource exhaustion.
@@ -119,6 +123,9 @@ impl Display for StartMicrovmError {
119123 AttachBlockDevice ( err) => {
120124 write ! ( f, "Unable to attach block device to Vmm: {}" , err)
121125 }
126+ BackingMemoryFile ( err) => {
127+ write ! ( f, "Unable to create the memory backing file: {}" , err)
128+ }
122129 ConfigureSystem ( e) => write ! ( f, "System configuration error: {:?}" , e) ,
123130 CreateRateLimiter ( err) => write ! ( f, "Cannot create RateLimiter: {}" , err) ,
124131 CreateNetDevice ( err) => {
@@ -238,7 +245,7 @@ fn create_vmm_and_vcpus(
238245 instance_info : & InstanceInfo ,
239246 event_manager : & mut EventManager ,
240247 guest_memory : GuestMemoryMmap ,
241- uffd : Option < Uffd > ,
248+ memory_descriptor : Option < MemoryDescriptor > ,
242249 track_dirty_pages : bool ,
243250 vcpu_count : u8 ,
244251) -> std:: result:: Result < ( Vmm , Vec < Vcpu > ) , StartMicrovmError > {
@@ -304,7 +311,7 @@ fn create_vmm_and_vcpus(
304311 shutdown_exit_code : None ,
305312 vm,
306313 guest_memory,
307- uffd ,
314+ memory_descriptor ,
308315 vcpus_handles : Vec :: new ( ) ,
309316 vcpus_exit_evt,
310317 mmio_device_manager,
@@ -336,8 +343,23 @@ pub fn build_microvm_for_boot(
336343 let boot_config = vm_resources. boot_source ( ) . ok_or ( MissingKernelConfig ) ?;
337344
338345 let track_dirty_pages = vm_resources. track_dirty_pages ( ) ;
339- let guest_memory =
340- create_guest_memory ( vm_resources. vm_config ( ) . mem_size_mib , track_dirty_pages) ?;
346+
347+ let backing_memory_file = if let Some ( ref file) = vm_resources. backing_memory_file {
348+ file. set_len ( ( vm_resources. vm_config ( ) . mem_size_mib * 1024 * 1024 ) as u64 )
349+ . map_err ( |e| {
350+ error ! ( "Failed to set backing memory file size: {}" , e) ;
351+ StartMicrovmError :: BackingMemoryFile ( e)
352+ } ) ?;
353+
354+ Some ( file. clone ( ) )
355+ } else {
356+ None
357+ } ;
358+ let guest_memory = create_guest_memory (
359+ vm_resources. vm_config ( ) . mem_size_mib ,
360+ backing_memory_file. clone ( ) ,
361+ track_dirty_pages,
362+ ) ?;
341363 let vcpu_config = vm_resources. vcpu_config ( ) ;
342364 let entry_addr = load_kernel ( boot_config, & guest_memory) ?;
343365 let initrd = load_initrd_from_config ( boot_config, & guest_memory) ?;
@@ -369,7 +391,7 @@ pub fn build_microvm_for_boot(
369391 instance_info,
370392 event_manager,
371393 guest_memory,
372- None ,
394+ backing_memory_file . map ( MemoryDescriptor :: File ) ,
373395 track_dirty_pages,
374396 vcpu_config. vcpu_count ,
375397 ) ?;
@@ -458,7 +480,7 @@ pub fn build_microvm_from_snapshot(
458480 event_manager : & mut EventManager ,
459481 microvm_state : MicrovmState ,
460482 guest_memory : GuestMemoryMmap ,
461- uffd : Option < Uffd > ,
483+ memory_descriptor : Option < MemoryDescriptor > ,
462484 track_dirty_pages : bool ,
463485 seccomp_filters : & BpfThreadMap ,
464486 vm_resources : & mut VmResources ,
@@ -473,7 +495,7 @@ pub fn build_microvm_from_snapshot(
473495 instance_info,
474496 event_manager,
475497 guest_memory. clone ( ) ,
476- uffd ,
498+ memory_descriptor ,
477499 track_dirty_pages,
478500 vcpu_count,
479501 ) ?;
@@ -590,15 +612,24 @@ pub fn build_microvm_from_snapshot(
590612/// Creates GuestMemory of `mem_size_mib` MiB in size.
591613pub fn create_guest_memory (
592614 mem_size_mib : usize ,
615+ backing_memory_file : Option < Arc < File > > ,
593616 track_dirty_pages : bool ,
594617) -> std:: result:: Result < GuestMemoryMmap , StartMicrovmError > {
595618 let mem_size = mem_size_mib << 20 ;
596619 let arch_mem_regions = arch:: arch_memory_regions ( mem_size) ;
597620
621+ let mut offset = 0_u64 ;
598622 vm_memory:: create_guest_memory (
599623 & arch_mem_regions
600624 . iter ( )
601- . map ( |( addr, size) | ( None , * addr, * size) )
625+ . map ( |( addr, size) | {
626+ let file_offset = backing_memory_file
627+ . clone ( )
628+ . map ( |file| FileOffset :: from_arc ( file, offset) ) ;
629+ offset += * size as u64 ;
630+
631+ ( file_offset, * addr, * size)
632+ } )
602633 . collect :: < Vec < _ > > ( ) [ ..] ,
603634 track_dirty_pages,
604635 )
@@ -1076,7 +1107,7 @@ pub mod tests {
10761107 }
10771108
10781109 pub ( crate ) fn default_vmm ( ) -> Vmm {
1079- let guest_memory = create_guest_memory ( 128 , false ) . unwrap ( ) ;
1110+ let guest_memory = create_guest_memory ( 128 , None , false ) . unwrap ( ) ;
10801111
10811112 let vcpus_exit_evt = EventFd :: new ( libc:: EFD_NONBLOCK )
10821113 . map_err ( Error :: EventFd )
@@ -1104,12 +1135,12 @@ pub mod tests {
11041135 shutdown_exit_code : None ,
11051136 vm,
11061137 guest_memory,
1107- uffd : None ,
11081138 vcpus_handles : Vec :: new ( ) ,
11091139 vcpus_exit_evt,
11101140 mmio_device_manager,
11111141 #[ cfg( target_arch = "x86_64" ) ]
11121142 pio_device_manager,
1143+ memory_descriptor : None ,
11131144 }
11141145 }
11151146
@@ -1291,21 +1322,21 @@ pub mod tests {
12911322
12921323 // Case 1: create guest memory without dirty page tracking
12931324 {
1294- let guest_memory = create_guest_memory ( mem_size, false ) . unwrap ( ) ;
1325+ let guest_memory = create_guest_memory ( mem_size, None , false ) . unwrap ( ) ;
12951326 assert ! ( !is_dirty_tracking_enabled( & guest_memory) ) ;
12961327 }
12971328
12981329 // Case 2: create guest memory with dirty page tracking
12991330 {
1300- let guest_memory = create_guest_memory ( mem_size, true ) . unwrap ( ) ;
1331+ let guest_memory = create_guest_memory ( mem_size, None , true ) . unwrap ( ) ;
13011332 assert ! ( is_dirty_tracking_enabled( & guest_memory) ) ;
13021333 }
13031334 }
13041335
13051336 #[ test]
13061337 fn test_create_vcpus ( ) {
13071338 let vcpu_count = 2 ;
1308- let guest_memory = create_guest_memory ( 128 , false ) . unwrap ( ) ;
1339+ let guest_memory = create_guest_memory ( 128 , None , false ) . unwrap ( ) ;
13091340
13101341 #[ allow( unused_mut) ]
13111342 let mut vm = setup_kvm_vm ( & guest_memory, false ) . unwrap ( ) ;
0 commit comments