@@ -22,9 +22,10 @@ pub use vm_memory::{
2222 GuestUsize , MemoryRegionAddress , MmapRegion , address,
2323} ;
2424use vm_memory:: { GuestMemoryError , GuestMemoryRegionBytes , VolatileSlice , WriteVolatile } ;
25- use vmm_sys_util:: errno;
25+ use vmm_sys_util:: fallocate:: FallocateMode ;
26+ use vmm_sys_util:: { errno, fallocate} ;
2627
27- use crate :: utils:: { get_page_size, u64_to_usize} ;
28+ use crate :: utils:: { get_page_size, u64_to_usize, usize_to_u64 } ;
2829use crate :: vmm_config:: machine_config:: HugePageConfig ;
2930use crate :: vstate:: vm:: VmError ;
3031use crate :: { DirtyBitmap , Vm } ;
@@ -391,8 +392,7 @@ impl GuestRegionMmapExt {
391392 let phys_address = self . get_host_address ( caddr) ?;
392393
393394 match ( self . inner . file_offset ( ) , self . inner . flags ( ) ) {
394- // If and only if we are resuming from a snapshot file, we have a file and it's mapped
395- // private
395+ // If we are resuming from a snapshot file, we have a file and it's mapped private
396396 ( Some ( _) , flags) if flags & libc:: MAP_PRIVATE != 0 => {
397397 // Mmap a new anonymous region over the present one in order to create a hole
398398 // with zero pages.
@@ -420,12 +420,29 @@ impl GuestRegionMmapExt {
420420 Ok ( ( ) )
421421 }
422422 }
423- // Match either the case of an anonymous mapping, or the case
424- // of a shared file mapping.
425- // TODO: madvise(MADV_DONTNEED) doesn't actually work with memfd
426- // (or in general MAP_SHARED of a fd). In those cases we should use
427- // fallocate64(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE).
428- // We keep falling to the madvise branch to keep the previous behaviour.
423+ // If we back memory over memfd we have a file mapped shared.
424+ ( Some ( file_offset) , flags) if flags & libc:: MAP_SHARED != 0 => {
425+ let Some ( offset) = file_offset. start ( ) . checked_add ( caddr. raw_value ( ) ) else {
426+ return Err ( GuestMemoryError :: InvalidGuestAddress ( GuestAddress (
427+ caddr. raw_value ( ) ,
428+ ) ) ) ;
429+ } ;
430+
431+ fallocate:: fallocate (
432+ file_offset. file ( ) ,
433+ FallocateMode :: PunchHole ,
434+ true ,
435+ offset,
436+ usize_to_u64 ( len) ,
437+ )
438+ . map_err ( |err| {
439+ error ! ( "discard_range: punching hole failed: {err:?}" ) ;
440+ GuestMemoryError :: IOError ( err. into ( ) )
441+ } ) ?;
442+
443+ Ok ( ( ) )
444+ }
445+ // Anonymous mapping.
429446 _ => {
430447 // Madvise the region in order to mark it as not used.
431448 // SAFETY: The address and length are known to be valid.
@@ -1462,6 +1479,32 @@ mod tests {
14621479 ) ;
14631480 }
14641481
1482+ #[ test]
1483+ fn test_discard_range_on_shared_memfd ( ) {
1484+ let page_size: usize = 0x1000 ;
1485+ let ( mem, _file) = memfd_backed (
1486+ & [ ( GuestAddress ( 0 ) , 2 * page_size) ] ,
1487+ false ,
1488+ HugePageConfig :: None ,
1489+ )
1490+ . unwrap ( ) ;
1491+ let mem = into_region_ext ( mem) ;
1492+
1493+ let ones = vec ! [ 1u8 ; 2 * page_size] ;
1494+ mem. write ( & ones, GuestAddress ( 0 ) ) . unwrap ( ) ;
1495+
1496+ mem. discard_range ( GuestAddress ( 0 ) , page_size) . unwrap ( ) ;
1497+
1498+ let mut actual_page = vec ! [ 0u8 ; page_size] ;
1499+ mem. read ( actual_page. as_mut_slice ( ) , GuestAddress ( 0 ) )
1500+ . unwrap ( ) ;
1501+ assert_eq ! ( vec![ 0u8 ; page_size] , actual_page) ;
1502+
1503+ mem. read ( actual_page. as_mut_slice ( ) , GuestAddress ( page_size as u64 ) )
1504+ . unwrap ( ) ;
1505+ assert_eq ! ( vec![ 1u8 ; page_size] , actual_page) ;
1506+ }
1507+
14651508 /// Verifies that `slots_intersecting_range` returns the correct slots for
14661509 /// ranges at slot boundaries, interior to a slot, and spanning two slots.
14671510 #[ test]
0 commit comments