Skip to content

Commit 96c70ea

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 506839a commit 96c70ea

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;
@@ -678,17 +679,62 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
678679
}
679680

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

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

0 commit comments

Comments
 (0)