diff options
-rw-r--r-- | sys_util/src/guest_memory.rs | 9 | ||||
-rw-r--r-- | sys_util/src/mmap.rs | 23 |
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. |