Skip to content

Commit f1718b8

Browse files
committed
Generalize GuestMemoryMmap to arbitrary GuestMemoryRegions
Add the concept of a `GuestRegionCollection`, which just manages a list of some `GuestMemoryRegion` impls. Functionality wise, it offers the same implementations as `GuestMemoryMmap`. As a result, turn `GuestMemoryMmap` into a type alias for `GuestRegionCollection` with a fixed `R = GuestRegionMmap`. The error type handling is a bit wack, but this is needed to preserve backwards compatibility: The error type of GuestRegionCollection must match what GuestMemoryMmap historically returned, so the error type needs to be lifted from mmap.rs - however, it contains specific variants that are only relevant to GuestMemoryMmap, so cfg those behind the `backend-mmap` feature flag (as to why this specific error type gets be privilege of just being reexported as `Error` from this crate: No idea, but its pre-existing, and changing it would be a breaking change). Signed-off-by: Patrick Roy <[email protected]>
1 parent 0d7765b commit f1718b8

File tree

4 files changed

+190
-159
lines changed

4 files changed

+190
-159
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
### Added
66

77
- \[[#311](https://github.com/rust-vmm/vm-memory/pull/311)\] Allow compiling without the ReadVolatile and WriteVolatile implementations
8+
- \[[#312](https://github.com/rust-vmm/vm-memory/pull/312)\] `GuestRegionContainer`, a generic container of `GuestMemoryRegion`s, generalizing `GuestMemoryMmap` (which
9+
is now a type alias for `GuestRegionContainer<GuestRegionMmap>`)
810

911
### Changed
1012

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub use guest_memory::{
5151
};
5252

5353
pub mod region;
54-
pub use region::GuestMemoryRegion;
54+
pub use region::{GuestMemoryRegion, GuestRegionCollection, GuestRegionError as Error};
5555

5656
pub mod io;
5757
pub use io::{ReadVolatile, WriteVolatile};
@@ -60,7 +60,7 @@ pub use io::{ReadVolatile, WriteVolatile};
6060
pub mod mmap;
6161

6262
#[cfg(feature = "backend-mmap")]
63-
pub use mmap::{Error, GuestMemoryMmap, GuestRegionMmap, MmapRegion};
63+
pub use mmap::{GuestMemoryMmap, GuestRegionMmap, MmapRegion};
6464
#[cfg(all(feature = "backend-mmap", feature = "xen", target_family = "unix"))]
6565
pub use mmap::{MmapRange, MmapXenFlags};
6666

src/mmap/mod.rs

Lines changed: 25 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,13 @@ use std::io::{Seek, SeekFrom};
1818
use std::ops::Deref;
1919
use std::result;
2020
use std::sync::atomic::Ordering;
21-
use std::sync::Arc;
2221

2322
use crate::address::Address;
2423
use crate::bitmap::{Bitmap, BS};
25-
use crate::guest_memory::{
26-
self, FileOffset, GuestAddress, GuestMemory, GuestUsize, MemoryRegionAddress,
27-
};
24+
use crate::guest_memory::{self, FileOffset, GuestAddress, GuestUsize, MemoryRegionAddress};
2825
use crate::region::GuestMemoryRegion;
2926
use crate::volatile_memory::{VolatileMemory, VolatileSlice};
30-
use crate::{AtomicAccess, Bytes, ReadVolatile, WriteVolatile};
27+
use crate::{AtomicAccess, Bytes, Error, GuestRegionCollection, ReadVolatile, WriteVolatile};
3128

3229
// re-export for backward compat, as the trait used to be defined in mmap.rs
3330
pub use crate::bitmap::NewBitmap;
@@ -52,27 +49,6 @@ pub use std::io::Error as MmapRegionError;
5249
#[cfg(target_family = "windows")]
5350
pub use windows::MmapRegion;
5451

55-
/// Errors that can occur when creating a memory map.
56-
#[derive(Debug, thiserror::Error)]
57-
pub enum Error {
58-
/// Adding the guest base address to the length of the underlying mapping resulted
59-
/// in an overflow.
60-
#[error("Adding the guest base address to the length of the underlying mapping resulted in an overflow")]
61-
InvalidGuestRegion,
62-
/// Error creating a `MmapRegion` object.
63-
#[error("{0}")]
64-
MmapRegion(MmapRegionError),
65-
/// No memory region found.
66-
#[error("No memory region found")]
67-
NoMemoryRegion,
68-
/// Some of the memory regions intersect with each other.
69-
#[error("Some of the memory regions intersect with each other")]
70-
MemoryRegionOverlap,
71-
/// The provided memory regions haven't been sorted.
72-
#[error("The provided memory regions haven't been sorted")]
73-
UnsortedMemoryRegions,
74-
}
75-
7652
// TODO: use this for Windows as well after we redefine the Error type there.
7753
#[cfg(target_family = "unix")]
7854
/// Checks if a mapping of `size` bytes fits at the provided `file_offset`.
@@ -369,17 +345,9 @@ impl<B: Bitmap> GuestMemoryRegion for GuestRegionMmap<B> {
369345
/// Represents the entire physical memory of the guest by tracking all its memory regions.
370346
/// Each region is an instance of `GuestRegionMmap`, being backed by a mapping in the
371347
/// virtual address space of the calling process.
372-
#[derive(Clone, Debug, Default)]
373-
pub struct GuestMemoryMmap<B = ()> {
374-
regions: Vec<Arc<GuestRegionMmap<B>>>,
375-
}
348+
pub type GuestMemoryMmap<B = ()> = GuestRegionCollection<GuestRegionMmap<B>>;
376349

377350
impl<B: NewBitmap> GuestMemoryMmap<B> {
378-
/// Creates an empty `GuestMemoryMmap` instance.
379-
pub fn new() -> Self {
380-
Self::default()
381-
}
382-
383351
/// Creates a container and allocates anonymous memory for guest memory regions.
384352
///
385353
/// Valid memory regions are specified as a slice of (Address, Size) tuples sorted by Address.
@@ -407,111 +375,6 @@ impl<B: NewBitmap> GuestMemoryMmap<B> {
407375
}
408376
}
409377

410-
impl<B: Bitmap> GuestMemoryMmap<B> {
411-
/// Creates a new `GuestMemoryMmap` from a vector of regions.
412-
///
413-
/// # Arguments
414-
///
415-
/// * `regions` - The vector of regions.
416-
/// The regions shouldn't overlap and they should be sorted
417-
/// by the starting address.
418-
pub fn from_regions(mut regions: Vec<GuestRegionMmap<B>>) -> result::Result<Self, Error> {
419-
Self::from_arc_regions(regions.drain(..).map(Arc::new).collect())
420-
}
421-
422-
/// Creates a new `GuestMemoryMmap` from a vector of Arc regions.
423-
///
424-
/// Similar to the constructor `from_regions()` as it returns a
425-
/// `GuestMemoryMmap`. The need for this constructor is to provide a way for
426-
/// consumer of this API to create a new `GuestMemoryMmap` based on existing
427-
/// regions coming from an existing `GuestMemoryMmap` instance.
428-
///
429-
/// # Arguments
430-
///
431-
/// * `regions` - The vector of `Arc` regions.
432-
/// The regions shouldn't overlap and they should be sorted
433-
/// by the starting address.
434-
pub fn from_arc_regions(regions: Vec<Arc<GuestRegionMmap<B>>>) -> result::Result<Self, Error> {
435-
if regions.is_empty() {
436-
return Err(Error::NoMemoryRegion);
437-
}
438-
439-
for window in regions.windows(2) {
440-
let prev = &window[0];
441-
let next = &window[1];
442-
443-
if prev.start_addr() > next.start_addr() {
444-
return Err(Error::UnsortedMemoryRegions);
445-
}
446-
447-
if prev.last_addr() >= next.start_addr() {
448-
return Err(Error::MemoryRegionOverlap);
449-
}
450-
}
451-
452-
Ok(Self { regions })
453-
}
454-
455-
/// Insert a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`.
456-
///
457-
/// # Arguments
458-
/// * `region`: the memory region to insert into the guest memory object.
459-
pub fn insert_region(
460-
&self,
461-
region: Arc<GuestRegionMmap<B>>,
462-
) -> result::Result<GuestMemoryMmap<B>, Error> {
463-
let mut regions = self.regions.clone();
464-
regions.push(region);
465-
regions.sort_by_key(|x| x.start_addr());
466-
467-
Self::from_arc_regions(regions)
468-
}
469-
470-
/// Remove a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`
471-
/// on success, together with the removed region.
472-
///
473-
/// # Arguments
474-
/// * `base`: base address of the region to be removed
475-
/// * `size`: size of the region to be removed
476-
pub fn remove_region(
477-
&self,
478-
base: GuestAddress,
479-
size: GuestUsize,
480-
) -> result::Result<(GuestMemoryMmap<B>, Arc<GuestRegionMmap<B>>), Error> {
481-
if let Ok(region_index) = self.regions.binary_search_by_key(&base, |x| x.start_addr()) {
482-
if self.regions.get(region_index).unwrap().mapping.size() as GuestUsize == size {
483-
let mut regions = self.regions.clone();
484-
let region = regions.remove(region_index);
485-
return Ok((Self { regions }, region));
486-
}
487-
}
488-
489-
Err(Error::InvalidGuestRegion)
490-
}
491-
}
492-
493-
impl<B: Bitmap + 'static> GuestMemory for GuestMemoryMmap<B> {
494-
type R = GuestRegionMmap<B>;
495-
496-
fn num_regions(&self) -> usize {
497-
self.regions.len()
498-
}
499-
500-
fn find_region(&self, addr: GuestAddress) -> Option<&GuestRegionMmap<B>> {
501-
let index = match self.regions.binary_search_by_key(&addr, |x| x.start_addr()) {
502-
Ok(x) => Some(x),
503-
// Within the closest region with starting address < addr
504-
Err(x) if (x > 0 && addr <= self.regions[x - 1].last_addr()) => Some(x - 1),
505-
_ => None,
506-
};
507-
index.map(|x| self.regions[x].as_ref())
508-
}
509-
510-
fn iter(&self) -> impl Iterator<Item = &Self::R> {
511-
self.regions.iter().map(AsRef::as_ref)
512-
}
513-
}
514-
515378
#[cfg(test)]
516379
mod tests {
517380
#![allow(clippy::undocumented_unsafe_blocks)]
@@ -521,16 +384,17 @@ mod tests {
521384

522385
use crate::bitmap::tests::test_guest_memory_and_region;
523386
use crate::bitmap::AtomicBitmap;
524-
use crate::GuestAddressSpace;
387+
use crate::{Error, GuestAddressSpace, GuestMemory};
525388

526389
use std::io::Write;
527390
use std::mem;
391+
use std::sync::Arc;
528392
#[cfg(feature = "rawfd")]
529393
use std::{fs::File, path::Path};
530394
use vmm_sys_util::tempfile::TempFile;
531395

532-
type GuestMemoryMmap = super::GuestMemoryMmap<()>;
533396
type GuestRegionMmap = super::GuestRegionMmap<()>;
397+
type GuestMemoryMmap = super::GuestRegionCollection<GuestRegionMmap>;
534398
type MmapRegion = super::MmapRegion<()>;
535399

536400
#[test]
@@ -555,9 +419,8 @@ mod tests {
555419
}
556420
assert_eq!(guest_mem.last_addr(), last_addr);
557421
}
558-
for ((region_addr, region_size), mmap) in expected_regions_summary
559-
.iter()
560-
.zip(guest_mem.regions.iter())
422+
for ((region_addr, region_size), mmap) in
423+
expected_regions_summary.iter().zip(guest_mem.iter())
561424
{
562425
assert_eq!(region_addr, &mmap.guest_base);
563426
assert_eq!(region_size, &mmap.mapping.size());
@@ -748,7 +611,7 @@ mod tests {
748611
let regions_summary = [(GuestAddress(0), 100_usize), (GuestAddress(100), 100_usize)];
749612

750613
let guest_mem = GuestMemoryMmap::new();
751-
assert_eq!(guest_mem.regions.len(), 0);
614+
assert_eq!(guest_mem.num_regions(), 0);
752615

753616
check_guest_memory_mmap(new_guest_memory_mmap(&regions_summary), &regions_summary);
754617

@@ -1086,8 +949,10 @@ mod tests {
1086949
.map(|x| (x.0, x.1))
1087950
.eq(iterated_regions.iter().copied()));
1088951

1089-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1090-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
952+
let mmap_regions = gm.iter().collect::<Vec<_>>();
953+
954+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
955+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1091956
}
1092957

1093958
#[test]
@@ -1115,8 +980,10 @@ mod tests {
1115980
.map(|x| (x.0, x.1))
1116981
.eq(iterated_regions.iter().copied()));
1117982

1118-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1119-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
983+
let mmap_regions = gm.iter().collect::<Vec<_>>();
984+
985+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
986+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1120987
}
1121988

1122989
#[test]
@@ -1225,11 +1092,13 @@ mod tests {
12251092
assert_eq!(mem_orig.num_regions(), 2);
12261093
assert_eq!(gm.num_regions(), 5);
12271094

1228-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1229-
assert_eq!(gm.regions[1].start_addr(), GuestAddress(0x4000));
1230-
assert_eq!(gm.regions[2].start_addr(), GuestAddress(0x8000));
1231-
assert_eq!(gm.regions[3].start_addr(), GuestAddress(0xc000));
1232-
assert_eq!(gm.regions[4].start_addr(), GuestAddress(0x10_0000));
1095+
let regions = gm.iter().collect::<Vec<_>>();
1096+
1097+
assert_eq!(regions[0].start_addr(), GuestAddress(0x0000));
1098+
assert_eq!(regions[1].start_addr(), GuestAddress(0x4000));
1099+
assert_eq!(regions[2].start_addr(), GuestAddress(0x8000));
1100+
assert_eq!(regions[3].start_addr(), GuestAddress(0xc000));
1101+
assert_eq!(regions[4].start_addr(), GuestAddress(0x10_0000));
12331102
}
12341103

12351104
#[test]
@@ -1250,7 +1119,7 @@ mod tests {
12501119
assert_eq!(mem_orig.num_regions(), 2);
12511120
assert_eq!(gm.num_regions(), 1);
12521121

1253-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1122+
assert_eq!(gm.iter().next().unwrap().start_addr(), GuestAddress(0x0000));
12541123
assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
12551124
}
12561125

0 commit comments

Comments
 (0)