From 2415ef6988700f796b46c62cc5462ba9e7d1ded2 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Mon, 6 Nov 2017 14:06:58 -0800 Subject: [PATCH] sys_util: Add ability to madvise a region Add functions to let the kernel know a given range of memory isn't needed currently. This function will result in `madvise(DONTNEED)`. The ability to signal memory as not needed will be used by the balloon driver to allow system memory to be redistributed away from the VM. Change-Id: I4ca56e09010eec33989824f5738db4a4be0ec428 Signed-off-by: Dylan Reid Reviewed-on: https://chromium-review.googlesource.com/759305 Reviewed-by: Zach Reizner --- sys_util/src/guest_memory.rs | 9 +++++++++ sys_util/src/mmap.rs | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs index 8e2dd9757c..2a849e99bf 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(&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 1d9ac9ecbc..9354311232 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.