55
66use std:: convert:: TryFrom ;
77use std:: fmt:: { Display , Formatter } ;
8+ use std:: fs:: File ;
89use std:: io:: { self , Read , Seek , SeekFrom } ;
910use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
1011use std:: sync:: { Arc , Mutex } ;
12+ use vm_memory:: FileOffset ;
1113
1214use arch:: InitrdConfig ;
1315#[ cfg( target_arch = "x86_64" ) ]
@@ -28,7 +30,6 @@ use linux_loader::loader::KernelLoader;
2830use logger:: { error, warn, METRICS } ;
2931use seccompiler:: BpfThreadMap ;
3032use snapshot:: Persist ;
31- use userfaultfd:: Uffd ;
3233use utils:: eventfd:: EventFd ;
3334use utils:: terminal:: Terminal ;
3435use utils:: time:: TimestampUs ;
@@ -43,7 +44,7 @@ use crate::construct_kvm_mpidrs;
4344use crate :: device_manager:: legacy:: PortIODeviceManager ;
4445use crate :: device_manager:: mmio:: MMIODeviceManager ;
4546use crate :: device_manager:: persist:: MMIODevManagerConstructorArgs ;
46- use crate :: persist:: { MicrovmState , MicrovmStateError } ;
47+ use crate :: persist:: { MemoryDescriptor , MicrovmState , MicrovmStateError } ;
4748use crate :: resources:: VmResources ;
4849use crate :: vmm_config:: boot_source:: BootConfig ;
4950use crate :: vmm_config:: instance_info:: InstanceInfo ;
@@ -58,6 +59,8 @@ use crate::{device_manager, mem_size_mib, Error, EventManager, Vmm, VmmEventsObs
5859pub enum StartMicrovmError {
5960 /// Unable to attach block device to Vmm.
6061 AttachBlockDevice ( io:: Error ) ,
62+ /// Unable to create the memory backing file.
63+ BackingMemoryFile ( io:: Error ) ,
6164 /// This error is thrown by the minimal boot loader implementation.
6265 ConfigureSystem ( arch:: Error ) ,
6366 /// Internal errors are due to resource exhaustion.
@@ -112,6 +115,9 @@ impl Display for StartMicrovmError {
112115 write ! ( f, "Unable to attach block device to Vmm: {}" , err)
113116 }
114117 ConfigureSystem ( err) => write ! ( f, "System configuration error: {:?}" , err) ,
118+ BackingMemoryFile ( err) => {
119+ write ! ( f, "Unable to create the memory backing file: {}" , err)
120+ }
115121 CreateRateLimiter ( err) => write ! ( f, "Cannot create RateLimiter: {}" , err) ,
116122 CreateNetDevice ( err) => {
117123 let mut err_msg = format ! ( "{:?}" , err) ;
@@ -231,7 +237,7 @@ fn create_vmm_and_vcpus(
231237 instance_info : & InstanceInfo ,
232238 event_manager : & mut EventManager ,
233239 guest_memory : GuestMemoryMmap ,
234- uffd : Option < Uffd > ,
240+ memory_descriptor : Option < MemoryDescriptor > ,
235241 track_dirty_pages : bool ,
236242 vcpu_count : u8 ,
237243) -> std:: result:: Result < ( Vmm , Vec < Vcpu > ) , StartMicrovmError > {
@@ -297,7 +303,7 @@ fn create_vmm_and_vcpus(
297303 shutdown_exit_code : None ,
298304 vm,
299305 guest_memory,
300- uffd ,
306+ memory_descriptor ,
301307 vcpus_handles : Vec :: new ( ) ,
302308 vcpus_exit_evt,
303309 mmio_device_manager,
@@ -329,8 +335,23 @@ pub fn build_microvm_for_boot(
329335 let boot_config = vm_resources. boot_source ( ) . ok_or ( MissingKernelConfig ) ?;
330336
331337 let track_dirty_pages = vm_resources. track_dirty_pages ( ) ;
332- let guest_memory =
333- create_guest_memory ( vm_resources. vm_config ( ) . mem_size_mib , track_dirty_pages) ?;
338+
339+ let backing_memory_file = if let Some ( ref file) = vm_resources. backing_memory_file {
340+ file. set_len ( ( vm_resources. vm_config ( ) . mem_size_mib * 1024 * 1024 ) as u64 )
341+ . map_err ( |e| {
342+ error ! ( "Failed to set backing memory file size: {}" , e) ;
343+ StartMicrovmError :: BackingMemoryFile ( e)
344+ } ) ?;
345+
346+ Some ( file. clone ( ) )
347+ } else {
348+ None
349+ } ;
350+ let guest_memory = create_guest_memory (
351+ vm_resources. vm_config ( ) . mem_size_mib ,
352+ backing_memory_file. clone ( ) ,
353+ track_dirty_pages,
354+ ) ?;
334355 let vcpu_config = vm_resources. vcpu_config ( ) ;
335356 let entry_addr = load_kernel ( boot_config, & guest_memory) ?;
336357 let initrd = load_initrd_from_config ( boot_config, & guest_memory) ?;
@@ -362,7 +383,7 @@ pub fn build_microvm_for_boot(
362383 instance_info,
363384 event_manager,
364385 guest_memory,
365- None ,
386+ backing_memory_file . map ( MemoryDescriptor :: File ) ,
366387 track_dirty_pages,
367388 vcpu_config. vcpu_count ,
368389 ) ?;
@@ -451,7 +472,7 @@ pub fn build_microvm_from_snapshot(
451472 event_manager : & mut EventManager ,
452473 microvm_state : MicrovmState ,
453474 guest_memory : GuestMemoryMmap ,
454- uffd : Option < Uffd > ,
475+ memory_descriptor : Option < MemoryDescriptor > ,
455476 track_dirty_pages : bool ,
456477 seccomp_filters : & BpfThreadMap ,
457478 vm_resources : & mut VmResources ,
@@ -466,7 +487,7 @@ pub fn build_microvm_from_snapshot(
466487 instance_info,
467488 event_manager,
468489 guest_memory. clone ( ) ,
469- uffd ,
490+ memory_descriptor ,
470491 track_dirty_pages,
471492 vcpu_count,
472493 ) ?;
@@ -581,15 +602,24 @@ pub fn build_microvm_from_snapshot(
581602/// Creates GuestMemory of `mem_size_mib` MiB in size.
582603pub fn create_guest_memory (
583604 mem_size_mib : usize ,
605+ backing_memory_file : Option < Arc < File > > ,
584606 track_dirty_pages : bool ,
585607) -> std:: result:: Result < GuestMemoryMmap , StartMicrovmError > {
586608 let mem_size = mem_size_mib << 20 ;
587609 let arch_mem_regions = arch:: arch_memory_regions ( mem_size) ;
588610
611+ let mut offset = 0_u64 ;
589612 vm_memory:: create_guest_memory (
590613 & arch_mem_regions
591614 . iter ( )
592- . map ( |( addr, size) | ( None , * addr, * size) )
615+ . map ( |( addr, size) | {
616+ let file_offset = backing_memory_file
617+ . clone ( )
618+ . map ( |file| FileOffset :: from_arc ( file, offset) ) ;
619+ offset += * size as u64 ;
620+
621+ ( file_offset, * addr, * size)
622+ } )
593623 . collect :: < Vec < _ > > ( ) [ ..] ,
594624 track_dirty_pages,
595625 )
@@ -1068,7 +1098,7 @@ pub mod tests {
10681098 }
10691099
10701100 pub ( crate ) fn default_vmm ( ) -> Vmm {
1071- let guest_memory = create_guest_memory ( 128 , false ) . unwrap ( ) ;
1101+ let guest_memory = create_guest_memory ( 128 , None , false ) . unwrap ( ) ;
10721102
10731103 let vcpus_exit_evt = EventFd :: new ( libc:: EFD_NONBLOCK )
10741104 . map_err ( Error :: EventFd )
@@ -1096,12 +1126,12 @@ pub mod tests {
10961126 shutdown_exit_code : None ,
10971127 vm,
10981128 guest_memory,
1099- uffd : None ,
11001129 vcpus_handles : Vec :: new ( ) ,
11011130 vcpus_exit_evt,
11021131 mmio_device_manager,
11031132 #[ cfg( target_arch = "x86_64" ) ]
11041133 pio_device_manager,
1134+ memory_descriptor : None ,
11051135 }
11061136 }
11071137
@@ -1283,21 +1313,21 @@ pub mod tests {
12831313
12841314 // Case 1: create guest memory without dirty page tracking
12851315 {
1286- let guest_memory = create_guest_memory ( mem_size, false ) . unwrap ( ) ;
1316+ let guest_memory = create_guest_memory ( mem_size, None , false ) . unwrap ( ) ;
12871317 assert ! ( !is_dirty_tracking_enabled( & guest_memory) ) ;
12881318 }
12891319
12901320 // Case 2: create guest memory with dirty page tracking
12911321 {
1292- let guest_memory = create_guest_memory ( mem_size, true ) . unwrap ( ) ;
1322+ let guest_memory = create_guest_memory ( mem_size, None , true ) . unwrap ( ) ;
12931323 assert ! ( is_dirty_tracking_enabled( & guest_memory) ) ;
12941324 }
12951325 }
12961326
12971327 #[ test]
12981328 fn test_create_vcpus ( ) {
12991329 let vcpu_count = 2 ;
1300- let guest_memory = create_guest_memory ( 128 , false ) . unwrap ( ) ;
1330+ let guest_memory = create_guest_memory ( 128 , None , false ) . unwrap ( ) ;
13011331
13021332 #[ allow( unused_mut) ]
13031333 let mut vm = setup_kvm_vm ( & guest_memory, false ) . unwrap ( ) ;
0 commit comments