@@ -37,7 +37,7 @@ const GUARD_PAGE_COUNT: usize = 1;
37
37
#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
38
38
pub enum MemoryError {
39
39
/// Cannot access file: {0:?}
40
- FileHandle ( std:: io:: Error ) ,
40
+ FileError ( std:: io:: Error ) ,
41
41
/// Cannot create memory: {0:?}
42
42
CreateMemory ( VmMemoryError ) ,
43
43
/// Cannot create memory region: {0:?}
@@ -50,13 +50,20 @@ pub enum MemoryError {
50
50
MmapRegionError ( MmapRegionError ) ,
51
51
/// Cannot create guest memory: {0}
52
52
VmMemoryError ( VmMemoryError ) ,
53
+ /// Cannot create memfd: {0:?}
54
+ Memfd ( memfd:: Error ) ,
55
+ /// Cannot resize memfd file: {0:?}
56
+ MemfdSetLen ( std:: io:: Error ) ,
53
57
}
54
58
55
59
/// Defines the interface for snapshotting memory.
56
60
pub trait GuestMemoryExtension
57
61
where
58
62
Self : Sized ,
59
63
{
64
+ /// Creates a GuestMemoryMmap with `size` in MiB and guard pages backed by file.
65
+ fn with_file ( file : & File , track_dirty_pages : bool ) -> Result < Self , MemoryError > ;
66
+
60
67
/// Creates a GuestMemoryMmap with `size` in MiB and guard pages.
61
68
fn with_size ( size : usize , track_dirty_pages : bool ) -> Result < Self , MemoryError > ;
62
69
@@ -119,15 +126,45 @@ pub struct GuestMemoryState {
119
126
}
120
127
121
128
impl GuestMemoryExtension for GuestMemoryMmap {
122
- /// Creates a GuestMemoryMmap with `size` in MiB and guard pages.
129
+ /// Creates a GuestMemoryMmap with `size` in MiB and guard pages backed by file.
130
+ fn with_file ( file : & File , track_dirty_pages : bool ) -> Result < Self , MemoryError > {
131
+ let metadata = file. metadata ( ) . map_err ( MemoryError :: FileError ) ?;
132
+ let mem_size = u64_to_usize ( metadata. len ( ) ) ;
133
+ let regions = crate :: arch:: arch_memory_regions ( mem_size) ;
134
+
135
+ let prot = libc:: PROT_READ | libc:: PROT_WRITE ;
136
+ let flags = libc:: MAP_NORESERVE | libc:: MAP_SHARED ;
137
+
138
+ let mut offset: u64 = 0 ;
139
+ let regions = regions
140
+ . iter ( )
141
+ . map ( |( guest_address, region_size) | {
142
+ let file_clone = file. try_clone ( ) . map_err ( MemoryError :: FileError ) ?;
143
+ let file_offset = FileOffset :: new ( file_clone, offset) ;
144
+ offset += * region_size as u64 ;
145
+ let region = build_guarded_region (
146
+ Some ( & file_offset) ,
147
+ * region_size,
148
+ prot,
149
+ flags,
150
+ track_dirty_pages,
151
+ ) ?;
152
+ GuestRegionMmap :: new ( region, * guest_address) . map_err ( MemoryError :: VmMemoryError )
153
+ } )
154
+ . collect :: < Result < Vec < _ > , MemoryError > > ( ) ?;
155
+
156
+ GuestMemoryMmap :: from_regions ( regions) . map_err ( MemoryError :: VmMemoryError )
157
+ }
158
+
159
+ /// Creates a GuestMemoryMmap with `size` in MiB and guard pages backed by anonymous memory.
123
160
fn with_size ( size : usize , track_dirty_pages : bool ) -> Result < Self , MemoryError > {
124
161
let mem_size = size << 20 ;
125
162
let regions = crate :: arch:: arch_memory_regions ( mem_size) ;
126
163
127
164
Self :: from_raw_regions ( & regions, track_dirty_pages)
128
165
}
129
166
130
- /// Creates a GuestMemoryMmap from raw regions with guard pages.
167
+ /// Creates a GuestMemoryMmap from raw regions with guard pages backed by anonymous memory .
131
168
fn from_raw_regions (
132
169
regions : & [ ( GuestAddress , usize ) ] ,
133
170
track_dirty_pages : bool ,
@@ -147,7 +184,7 @@ impl GuestMemoryExtension for GuestMemoryMmap {
147
184
GuestMemoryMmap :: from_regions ( regions) . map_err ( MemoryError :: VmMemoryError )
148
185
}
149
186
150
- /// Creates a GuestMemoryMmap from raw regions with no guard pages.
187
+ /// Creates a GuestMemoryMmap from raw regions with no guard pages backed by anonymous memory .
151
188
fn from_raw_regions_unguarded (
152
189
regions : & [ ( GuestAddress , usize ) ] ,
153
190
track_dirty_pages : bool ,
@@ -195,7 +232,7 @@ impl GuestMemoryExtension for GuestMemoryMmap {
195
232
} )
196
233
} )
197
234
. collect :: < Result < Vec < _ > , std:: io:: Error > > ( )
198
- . map_err ( MemoryError :: FileHandle ) ?;
235
+ . map_err ( MemoryError :: FileError ) ?;
199
236
200
237
let prot = libc:: PROT_READ | libc:: PROT_WRITE ;
201
238
let flags = libc:: MAP_NORESERVE | libc:: MAP_PRIVATE ;
@@ -322,6 +359,33 @@ impl GuestMemoryExtension for GuestMemoryMmap {
322
359
}
323
360
}
324
361
362
+ /// Creates a memfd file with the `size` in MiB.
363
+ pub fn create_memfd ( size : usize ) -> Result < memfd:: Memfd , MemoryError > {
364
+ let mem_size = size << 20 ;
365
+ // Create a memfd.
366
+ let opts = memfd:: MemfdOptions :: default ( ) . allow_sealing ( true ) ;
367
+ let mem_file = opts. create ( "guest_mem" ) . map_err ( MemoryError :: Memfd ) ?;
368
+
369
+ // Resize to guest mem size.
370
+ mem_file
371
+ . as_file ( )
372
+ . set_len ( mem_size as u64 )
373
+ . map_err ( MemoryError :: MemfdSetLen ) ?;
374
+
375
+ // Add seals to prevent further resizing.
376
+ let mut seals = memfd:: SealsHashSet :: new ( ) ;
377
+ seals. insert ( memfd:: FileSeal :: SealShrink ) ;
378
+ seals. insert ( memfd:: FileSeal :: SealGrow ) ;
379
+ mem_file. add_seals ( & seals) . map_err ( MemoryError :: Memfd ) ?;
380
+
381
+ // Prevent further sealing changes.
382
+ mem_file
383
+ . add_seal ( memfd:: FileSeal :: SealSeal )
384
+ . map_err ( MemoryError :: Memfd ) ?;
385
+
386
+ Ok ( mem_file)
387
+ }
388
+
325
389
/// Build a `MmapRegion` surrounded by guard pages.
326
390
///
327
391
/// Initially, we map a `PROT_NONE` guard region of size:
@@ -844,4 +908,19 @@ mod tests {
844
908
assert_eq ! ( expected_first_region, diff_file_content) ;
845
909
}
846
910
}
911
+
912
+ #[ test]
913
+ fn test_create_memfd ( ) {
914
+ let size = 1 ;
915
+ let size_mb = 1 << 20 ;
916
+
917
+ let memfd = create_memfd ( size) . unwrap ( ) ;
918
+
919
+ assert_eq ! ( memfd. as_file( ) . metadata( ) . unwrap( ) . len( ) , size_mb) ;
920
+ assert ! ( memfd. as_file( ) . set_len( 0x69 ) . is_err( ) ) ;
921
+
922
+ let mut seals = memfd:: SealsHashSet :: new ( ) ;
923
+ seals. insert ( memfd:: FileSeal :: SealGrow ) ;
924
+ assert ! ( memfd. add_seals( & seals) . is_err( ) ) ;
925
+ }
847
926
}
0 commit comments