summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--sys_util/src/guest_memory.rs9
-rw-r--r--sys_util/src/mmap.rs23
2 files changed, 32 insertions, 0 deletions
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
index 8e2dd97..2a849e9 100644
--- a/sys_util/src/guest_memory.rs
+++ b/sys_util/src/guest_memory.rs
@@ -105,6 +105,15 @@ impl GuestMemory {
         self.regions.len()
     }
 
+    /// Madvise away the address range in the host that is associated with the given guest range.
+    pub fn dont_need_range(&self, addr: GuestAddress, count: usize) -> Result<()> {
+        self.do_in_region(addr, move |mapping, offset| {
+            mapping
+                .dont_need_range(offset, count)
+                .map_err(|e| Error::MemoryAccess(addr, e))
+        })
+    }
+
     /// Perform the specified action on each region's addresses.
     pub fn with_regions<F, E>(&self, cb: F) -> result::Result<(), E>
         where F: Fn(usize, GuestAddress, usize, usize) -> result::Result<(), E>
diff --git a/sys_util/src/mmap.rs b/sys_util/src/mmap.rs
index 1d9ac9e..9354311 100644
--- a/sys_util/src/mmap.rs
+++ b/sys_util/src/mmap.rs
@@ -299,6 +299,29 @@ impl MemoryMapping {
         Ok(())
     }
 
+    /// Uses madvise to tell the kernel the specified range won't be needed soon.
+    pub fn dont_need_range(&self, mem_offset: usize, count: usize) -> Result<()> {
+        let mem_end = match mem_offset.checked_add(count) {
+            None => return Err(Error::InvalidRange(mem_offset, count)),
+            Some(m) => m,
+        };
+        if mem_end > self.size() {
+            return Err(Error::InvalidRange(mem_offset, count));
+        }
+        let ret = unsafe {
+            // madvising away the region is the same as the guest changing it.
+            // Next time it is read, it may return zero pages.
+            libc::madvise((self.addr as usize + mem_offset) as *mut _,
+                          count,
+                          libc::MADV_DONTNEED)
+        };
+        if ret < 0 {
+            Err(Error::InvalidRange(mem_offset, count))
+        } else {
+            Ok(())
+        }
+    }
+
     unsafe fn as_slice(&self) -> &[u8] {
         // This is safe because we mapped the area at addr ourselves, so this slice will not
         // overflow. However, it is possible to alias.