@@ -116,43 +116,52 @@ impl GuestRegionMmapExt {
116116 ) -> Result < ( ) , GuestMemoryError > {
117117 let phys_address = self . get_host_address ( caddr) ?;
118118
119- // If and only if we are resuming from a snapshot file, we have a file and it's mapped
120- // private
121- if self . inner . file_offset ( ) . is_some ( ) && self . inner . flags ( ) & libc:: MAP_PRIVATE != 0 {
122- // Mmap a new anonymous region over the present one in order to create a hole
123- // with zero pages.
124- // This workaround is (only) needed after resuming from a snapshot file because the
125- // guest memory is mmaped from file as private. In this case, MADV_DONTNEED on the
126- // file only drops any anonymous pages in range, but subsequent accesses would read
127- // whatever page is stored on the backing file. Mmapping anonymous pages ensures it's
128- // zeroed.
129- // SAFETY: The address and length are known to be valid.
130- let ret = unsafe {
131- libc:: mmap (
132- phys_address. cast ( ) ,
133- len,
134- libc:: PROT_READ | libc:: PROT_WRITE ,
135- libc:: MAP_FIXED | libc:: MAP_ANONYMOUS | libc:: MAP_PRIVATE ,
136- -1 ,
137- 0 ,
138- )
139- } ;
140- if ret == libc:: MAP_FAILED {
141- let os_error = std:: io:: Error :: last_os_error ( ) ;
142- error ! ( "discard_range: mmap failed: {:?}" , os_error) ;
143- return Err ( GuestMemoryError :: IOError ( os_error) ) ;
119+ match ( self . inner . file_offset ( ) , self . inner . flags ( ) ) {
120+ // If and only if we are resuming from a snapshot file, we have a file and it's mapped
121+ // private
122+ ( Some ( _) , flags) if flags & libc:: MAP_PRIVATE != 0 => {
123+ // Mmap a new anonymous region over the present one in order to create a hole
124+ // with zero pages.
125+ // This workaround is (only) needed after resuming from a snapshot file because the
126+ // guest memory is mmaped from file as private. In this case, MADV_DONTNEED on the
127+ // file only drops any anonymous pages in range, but subsequent accesses would read
128+ // whatever page is stored on the backing file. Mmapping anonymous pages ensures
129+ // it's zeroed.
130+ // SAFETY: The address and length are known to be valid.
131+ let ret = unsafe {
132+ libc:: mmap (
133+ phys_address. cast ( ) ,
134+ len,
135+ libc:: PROT_READ | libc:: PROT_WRITE ,
136+ libc:: MAP_FIXED | libc:: MAP_ANONYMOUS | libc:: MAP_PRIVATE ,
137+ -1 ,
138+ 0 ,
139+ )
140+ } ;
141+ if ret == libc:: MAP_FAILED {
142+ let os_error = std:: io:: Error :: last_os_error ( ) ;
143+ error ! ( "discard_range: mmap failed: {:?}" , os_error) ;
144+ Err ( GuestMemoryError :: IOError ( os_error) )
145+ } else {
146+ Ok ( ( ) )
147+ }
148+ }
149+ // TODO: madvise(MADV_DONTNEED) doesn't actually work with memfd
150+ // (or in general MAP_SHARED of a fd). In those cases we should use
151+ // fallocate64(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE).
152+ // We keep falling to the madvise branch to keep the previous behaviour.
153+ ( None , _) | ( Some ( _) , _) => {
154+ // Madvise the region in order to mark it as not used.
155+ // SAFETY: The address and length are known to be valid.
156+ let ret = unsafe { libc:: madvise ( phys_address. cast ( ) , len, libc:: MADV_DONTNEED ) } ;
157+ if ret < 0 {
158+ let os_error = std:: io:: Error :: last_os_error ( ) ;
159+ error ! ( "discard_range: madvise failed: {:?}" , os_error) ;
160+ Err ( GuestMemoryError :: IOError ( os_error) )
161+ } else {
162+ Ok ( ( ) )
163+ }
144164 }
145- }
146-
147- // Madvise the region in order to mark it as not used.
148- // SAFETY: The address and length are known to be valid.
149- let ret = unsafe { libc:: madvise ( phys_address. cast ( ) , len, libc:: MADV_DONTNEED ) } ;
150- if ret < 0 {
151- let os_error = std:: io:: Error :: last_os_error ( ) ;
152- error ! ( "discard_range: madvise failed: {:?}" , os_error) ;
153- Err ( GuestMemoryError :: IOError ( os_error) )
154- } else {
155- Ok ( ( ) )
156165 }
157166 }
158167}
0 commit comments