Skip to content

Commit 6d42950

Browse files
committed
Bytes: Do not use to_region_addr()
When we switch to a (potentially) virtual memory model, we want to compact the interface, especially removing references to memory regions because virtual memory is not just split into regions, but pages first. The one memory-region-referencing part we are going to keep is `try_access()` because that method is nicely structured around the fragmentation we will have to accept when it comes to paged memory. `to_region_addr()` in contrast does not even take a length argument, so for virtual memory, using the returned region and address is unsafe if doing so crosses page boundaries. Therefore, switch `Bytes::load()` and `store()` from using `to_region_addr()` to `try_access()`. (Note: We cannot really have a test case for this, as right now, memory fragmentation will only happen exactly at memory region boundaries. In this case, `region.load()` and `region.store()` would have already returned errors. This change is necessary for when page boundaries result in different mappings within a single region, but because we don’t have IOMMU support yet, this can’t be tested.) Signed-off-by: Hanna Czenczek <[email protected]>
1 parent d2dc8a4 commit 6d42950

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
Change return type of `GuestRegionMmap::new` from `Result` to `Option`.
2525
- \[#324](https:////github.com/rust-vmm/vm-memory/pull/324)\] `GuestMemoryRegion::bitmap()` now returns a `BitmapSlice`. Accessing the full bitmap is now possible only if the type of the memory region is know, for example with `MmapRegion::bitmap()`.
2626
- \[[#339](https://github.com/rust-vmm/vm-memory/pull/339)\] Fix `Bytes::read()` and `Bytes::write()` not to ignore `try_access()`'s `count` parameter
27+
- \[[#339](https://github.com/rust-vmm/vm-memory/pull/339)\] Implement `Bytes::load()` and `Bytes::store()` with `try_access()` instead of `to_region_addr()`
2728

2829
### Removed
2930

src/guest_memory.rs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
use std::convert::From;
4545
use std::fs::File;
4646
use std::io;
47+
use std::mem::size_of;
4748
use std::ops::{BitAnd, BitOr, Deref};
4849
use std::rc::Rc;
4950
use std::sync::atomic::Ordering;
@@ -677,17 +678,62 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
677678
}
678679

679680
fn store<O: AtomicAccess>(&self, val: O, addr: GuestAddress, order: Ordering) -> Result<()> {
680-
// `find_region` should really do what `to_region_addr` is doing right now, except
681-
// it should keep returning a `Result`.
682-
self.to_region_addr(addr)
683-
.ok_or(Error::InvalidGuestAddress(addr))
684-
.and_then(|(region, region_addr)| region.store(val, region_addr, order))
681+
let expected = size_of::<O>();
682+
683+
let completed = self.try_access(
684+
expected,
685+
addr,
686+
|offset, len, region_addr, region| -> Result<usize> {
687+
assert_eq!(offset, 0);
688+
if len < expected {
689+
return Err(Error::PartialBuffer {
690+
expected,
691+
completed: 0,
692+
});
693+
}
694+
region.store(val, region_addr, order).map(|()| expected)
695+
},
696+
)?;
697+
698+
if completed < expected {
699+
Err(Error::PartialBuffer {
700+
expected,
701+
completed,
702+
})
703+
} else {
704+
Ok(())
705+
}
685706
}
686707

687708
fn load<O: AtomicAccess>(&self, addr: GuestAddress, order: Ordering) -> Result<O> {
688-
self.to_region_addr(addr)
689-
.ok_or(Error::InvalidGuestAddress(addr))
690-
.and_then(|(region, region_addr)| region.load(region_addr, order))
709+
let expected = size_of::<O>();
710+
let mut result = None::<O>;
711+
712+
let completed = self.try_access(
713+
expected,
714+
addr,
715+
|offset, len, region_addr, region| -> Result<usize> {
716+
assert_eq!(offset, 0);
717+
if len < expected {
718+
return Err(Error::PartialBuffer {
719+
expected,
720+
completed: 0,
721+
});
722+
}
723+
result = Some(region.load(region_addr, order)?);
724+
Ok(expected)
725+
},
726+
)?;
727+
728+
if completed < expected {
729+
Err(Error::PartialBuffer {
730+
expected,
731+
completed,
732+
})
733+
} else {
734+
// Must be set because `completed == expected`
735+
Ok(result.unwrap())
736+
}
691737
}
692738
}
693739

0 commit comments

Comments
 (0)