5
5
6
6
use std:: convert:: TryFrom ;
7
7
use std:: fmt:: { Display , Formatter } ;
8
+ use std:: fs:: File ;
8
9
use std:: io:: { self , Read , Seek , SeekFrom } ;
9
10
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
10
11
use std:: sync:: { Arc , Mutex } ;
12
+ use vm_memory:: FileOffset ;
11
13
12
14
use arch:: InitrdConfig ;
13
15
#[ cfg( target_arch = "x86_64" ) ]
@@ -28,7 +30,6 @@ use linux_loader::loader::KernelLoader;
28
30
use logger:: { error, warn, METRICS } ;
29
31
use seccompiler:: BpfThreadMap ;
30
32
use snapshot:: Persist ;
31
- use userfaultfd:: Uffd ;
32
33
use utils:: eventfd:: EventFd ;
33
34
use utils:: terminal:: Terminal ;
34
35
use utils:: time:: TimestampUs ;
@@ -43,7 +44,7 @@ use crate::construct_kvm_mpidrs;
43
44
use crate :: device_manager:: legacy:: PortIODeviceManager ;
44
45
use crate :: device_manager:: mmio:: MMIODeviceManager ;
45
46
use crate :: device_manager:: persist:: MMIODevManagerConstructorArgs ;
46
- use crate :: persist:: { MicrovmState , MicrovmStateError } ;
47
+ use crate :: persist:: { MemoryDescriptor , MicrovmState , MicrovmStateError } ;
47
48
use crate :: resources:: VmResources ;
48
49
use crate :: vmm_config:: boot_source:: BootConfig ;
49
50
use crate :: vmm_config:: instance_info:: InstanceInfo ;
@@ -58,6 +59,8 @@ use crate::{device_manager, mem_size_mib, Error, EventManager, Vmm, VmmEventsObs
58
59
pub enum StartMicrovmError {
59
60
/// Unable to attach block device to Vmm.
60
61
AttachBlockDevice ( io:: Error ) ,
62
+ /// Unable to create the memory backing file.
63
+ BackingMemoryFile ( io:: Error ) ,
61
64
/// This error is thrown by the minimal boot loader implementation.
62
65
ConfigureSystem ( arch:: Error ) ,
63
66
/// Internal errors are due to resource exhaustion.
@@ -112,6 +115,9 @@ impl Display for StartMicrovmError {
112
115
write ! ( f, "Unable to attach block device to Vmm: {}" , err)
113
116
}
114
117
ConfigureSystem ( err) => write ! ( f, "System configuration error: {:?}" , err) ,
118
+ BackingMemoryFile ( err) => {
119
+ write ! ( f, "Unable to create the memory backing file: {}" , err)
120
+ }
115
121
CreateRateLimiter ( err) => write ! ( f, "Cannot create RateLimiter: {}" , err) ,
116
122
CreateNetDevice ( err) => {
117
123
let mut err_msg = format ! ( "{:?}" , err) ;
@@ -231,7 +237,7 @@ fn create_vmm_and_vcpus(
231
237
instance_info : & InstanceInfo ,
232
238
event_manager : & mut EventManager ,
233
239
guest_memory : GuestMemoryMmap ,
234
- uffd : Option < Uffd > ,
240
+ memory_descriptor : Option < MemoryDescriptor > ,
235
241
track_dirty_pages : bool ,
236
242
vcpu_count : u8 ,
237
243
) -> std:: result:: Result < ( Vmm , Vec < Vcpu > ) , StartMicrovmError > {
@@ -297,7 +303,7 @@ fn create_vmm_and_vcpus(
297
303
shutdown_exit_code : None ,
298
304
vm,
299
305
guest_memory,
300
- uffd ,
306
+ memory_descriptor ,
301
307
vcpus_handles : Vec :: new ( ) ,
302
308
vcpus_exit_evt,
303
309
mmio_device_manager,
@@ -329,8 +335,23 @@ pub fn build_microvm_for_boot(
329
335
let boot_config = vm_resources. boot_source ( ) . ok_or ( MissingKernelConfig ) ?;
330
336
331
337
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
+ ) ?;
334
355
let vcpu_config = vm_resources. vcpu_config ( ) ;
335
356
let entry_addr = load_kernel ( boot_config, & guest_memory) ?;
336
357
let initrd = load_initrd_from_config ( boot_config, & guest_memory) ?;
@@ -362,7 +383,7 @@ pub fn build_microvm_for_boot(
362
383
instance_info,
363
384
event_manager,
364
385
guest_memory,
365
- None ,
386
+ backing_memory_file . map ( MemoryDescriptor :: File ) ,
366
387
track_dirty_pages,
367
388
vcpu_config. vcpu_count ,
368
389
) ?;
@@ -451,7 +472,7 @@ pub fn build_microvm_from_snapshot(
451
472
event_manager : & mut EventManager ,
452
473
microvm_state : MicrovmState ,
453
474
guest_memory : GuestMemoryMmap ,
454
- uffd : Option < Uffd > ,
475
+ memory_descriptor : Option < MemoryDescriptor > ,
455
476
track_dirty_pages : bool ,
456
477
seccomp_filters : & BpfThreadMap ,
457
478
vm_resources : & mut VmResources ,
@@ -466,7 +487,7 @@ pub fn build_microvm_from_snapshot(
466
487
instance_info,
467
488
event_manager,
468
489
guest_memory. clone ( ) ,
469
- uffd ,
490
+ memory_descriptor ,
470
491
track_dirty_pages,
471
492
vcpu_count,
472
493
) ?;
@@ -581,15 +602,24 @@ pub fn build_microvm_from_snapshot(
581
602
/// Creates GuestMemory of `mem_size_mib` MiB in size.
582
603
pub fn create_guest_memory (
583
604
mem_size_mib : usize ,
605
+ backing_memory_file : Option < Arc < File > > ,
584
606
track_dirty_pages : bool ,
585
607
) -> std:: result:: Result < GuestMemoryMmap , StartMicrovmError > {
586
608
let mem_size = mem_size_mib << 20 ;
587
609
let arch_mem_regions = arch:: arch_memory_regions ( mem_size) ;
588
610
611
+ let mut offset = 0_u64 ;
589
612
vm_memory:: create_guest_memory (
590
613
& arch_mem_regions
591
614
. 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
+ } )
593
623
. collect :: < Vec < _ > > ( ) [ ..] ,
594
624
track_dirty_pages,
595
625
)
@@ -1068,7 +1098,7 @@ pub mod tests {
1068
1098
}
1069
1099
1070
1100
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 ( ) ;
1072
1102
1073
1103
let vcpus_exit_evt = EventFd :: new ( libc:: EFD_NONBLOCK )
1074
1104
. map_err ( Error :: EventFd )
@@ -1096,12 +1126,12 @@ pub mod tests {
1096
1126
shutdown_exit_code : None ,
1097
1127
vm,
1098
1128
guest_memory,
1099
- uffd : None ,
1100
1129
vcpus_handles : Vec :: new ( ) ,
1101
1130
vcpus_exit_evt,
1102
1131
mmio_device_manager,
1103
1132
#[ cfg( target_arch = "x86_64" ) ]
1104
1133
pio_device_manager,
1134
+ memory_descriptor : None ,
1105
1135
}
1106
1136
}
1107
1137
@@ -1283,21 +1313,21 @@ pub mod tests {
1283
1313
1284
1314
// Case 1: create guest memory without dirty page tracking
1285
1315
{
1286
- let guest_memory = create_guest_memory ( mem_size, false ) . unwrap ( ) ;
1316
+ let guest_memory = create_guest_memory ( mem_size, None , false ) . unwrap ( ) ;
1287
1317
assert ! ( !is_dirty_tracking_enabled( & guest_memory) ) ;
1288
1318
}
1289
1319
1290
1320
// Case 2: create guest memory with dirty page tracking
1291
1321
{
1292
- let guest_memory = create_guest_memory ( mem_size, true ) . unwrap ( ) ;
1322
+ let guest_memory = create_guest_memory ( mem_size, None , true ) . unwrap ( ) ;
1293
1323
assert ! ( is_dirty_tracking_enabled( & guest_memory) ) ;
1294
1324
}
1295
1325
}
1296
1326
1297
1327
#[ test]
1298
1328
fn test_create_vcpus ( ) {
1299
1329
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 ( ) ;
1301
1331
1302
1332
#[ allow( unused_mut) ]
1303
1333
let mut vm = setup_kvm_vm ( & guest_memory, false ) . unwrap ( ) ;
0 commit comments