From 1e9e33179940d93fdf6e8979ae48953092d7b74d Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 1 Oct 2019 10:51:45 -0700 Subject: [PATCH] guest_memory: make do_in_region(..) callback take memfd offset Useful for the udmabuf use case. The current offset used by the callback is relative to the mapping, not the absolute memfd offset. BUG=chromium:892806, b:173630595 TEST=cargo test -p vm_memory Change-Id: I57d02d016888a2d974f1f9e359375cb0941dc949 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2786289 Tested-by: kokoro Tested-by: Gurchetan Singh Commit-Queue: Gurchetan Singh Reviewed-by: Daniel Verkamp --- vm_memory/src/guest_memory.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/vm_memory/src/guest_memory.rs b/vm_memory/src/guest_memory.rs index b160968b81..f01e050021 100644 --- a/vm_memory/src/guest_memory.rs +++ b/vm_memory/src/guest_memory.rs @@ -252,7 +252,7 @@ impl GuestMemory { /// Madvise away the address range in the host that is associated with the given guest range. pub fn remove_range(&self, addr: GuestAddress, count: u64) -> Result<()> { - self.do_in_region(addr, move |mapping, offset| { + self.do_in_region(addr, move |mapping, offset, _| { mapping .remove_range(offset, count as usize) .map_err(|e| Error::MemoryAccess(addr, e)) @@ -303,7 +303,7 @@ impl GuestMemory { /// # } /// ``` pub fn write_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result { - self.do_in_region(guest_addr, move |mapping, offset| { + self.do_in_region(guest_addr, move |mapping, offset, _| { mapping .write_slice(buf, offset) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -362,7 +362,7 @@ impl GuestMemory { /// # } /// ``` pub fn read_at_addr(&self, buf: &mut [u8], guest_addr: GuestAddress) -> Result { - self.do_in_region(guest_addr, move |mapping, offset| { + self.do_in_region(guest_addr, move |mapping, offset, _| { mapping .read_slice(buf, offset) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -422,7 +422,7 @@ impl GuestMemory { /// # } /// ``` pub fn read_obj_from_addr(&self, guest_addr: GuestAddress) -> Result { - self.do_in_region(guest_addr, |mapping, offset| { + self.do_in_region(guest_addr, |mapping, offset, _| { mapping .read_obj(offset) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -446,7 +446,7 @@ impl GuestMemory { /// # } /// ``` pub fn write_obj_at_addr(&self, val: T, guest_addr: GuestAddress) -> Result<()> { - self.do_in_region(guest_addr, move |mapping, offset| { + self.do_in_region(guest_addr, move |mapping, offset, _| { mapping .write_obj(val, offset) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -543,7 +543,7 @@ impl GuestMemory { src: &dyn AsRawDescriptor, count: usize, ) -> Result<()> { - self.do_in_region(guest_addr, move |mapping, offset| { + self.do_in_region(guest_addr, move |mapping, offset, _| { mapping .read_to_memory(offset, src, count) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -581,7 +581,7 @@ impl GuestMemory { dst: &dyn AsRawDescriptor, count: usize, ) -> Result<()> { - self.do_in_region(guest_addr, move |mapping, offset| { + self.do_in_region(guest_addr, move |mapping, offset, _| { mapping .write_from_memory(offset, dst, count) .map_err(|e| Error::MemoryAccess(guest_addr, e)) @@ -609,16 +609,25 @@ impl GuestMemory { /// # } /// ``` pub fn get_host_address(&self, guest_addr: GuestAddress) -> Result<*const u8> { - self.do_in_region(guest_addr, |mapping, offset| { + self.do_in_region(guest_addr, |mapping, offset, _| { // This is safe; `do_in_region` already checks that offset is in // bounds. Ok(unsafe { mapping.as_ptr().add(offset) } as *const u8) }) } + /// Loops over all guest memory regions of `self`, and performs the callback function `F` in + /// the target region that contains `guest_addr`. The callback function `F` takes in: + /// + /// (i) the memory mapping associated with the target region. + /// (ii) the relative offset from the start of the target region to `guest_addr`. + /// (iii) the absolute offset from the start of the memory mapping to the target region. + /// + /// If no target region is found, an error is returned. The callback function `F` may return + /// an Ok(`T`) on success or a `GuestMemoryError` on failure. pub fn do_in_region(&self, guest_addr: GuestAddress, cb: F) -> Result where - F: FnOnce(&MemoryMapping, usize) -> Result, + F: FnOnce(&MemoryMapping, usize, u64) -> Result, { self.regions .iter() @@ -628,6 +637,7 @@ impl GuestMemory { cb( ®ion.mapping, guest_addr.offset_from(region.start()) as usize, + region.memfd_offset, ) }) } @@ -800,7 +810,7 @@ mod tests { // Get the base address of the mapping for a GuestAddress. fn get_mapping(mem: &GuestMemory, addr: GuestAddress) -> Result<*const u8> { - mem.do_in_region(addr, |mapping, _| Ok(mapping.as_ptr() as *const u8)) + mem.do_in_region(addr, |mapping, _, _| Ok(mapping.as_ptr() as *const u8)) } #[test]