Skip to content

Commit 2c8f95d

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 60e582d commit 2c8f95d

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};
@@ -69,7 +69,7 @@ mod mmap_windows;
6969
pub mod mmap;
7070

7171
#[cfg(feature = "backend-mmap")]
72-
pub use mmap::{Error, GuestMemoryMmap, GuestRegionMmap, MmapRegion};
72+
pub use mmap::{GuestMemoryMmap, GuestRegionMmap, MmapRegion};
7373
#[cfg(all(feature = "backend-mmap", feature = "xen", unix))]
7474
pub use mmap::{MmapRange, MmapXenFlags};
7575

src/mmap.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
#[cfg(all(not(feature = "xen"), unix))]
3330
pub use crate::mmap_unix::{Error as MmapRegionError, MmapRegion, MmapRegionBuilder};
@@ -50,27 +47,6 @@ impl NewBitmap for () {
5047
fn with_len(_len: usize) -> Self {}
5148
}
5249

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

375348
impl<B: NewBitmap> GuestMemoryMmap<B> {
376-
/// Creates an empty `GuestMemoryMmap` instance.
377-
pub fn new() -> Self {
378-
Self::default()
379-
}
380-
381349
/// Creates a container and allocates anonymous memory for guest memory regions.
382350
///
383351
/// Valid memory regions are specified as a slice of (Address, Size) tuples sorted by Address.
@@ -405,111 +373,6 @@ impl<B: NewBitmap> GuestMemoryMmap<B> {
405373
}
406374
}
407375

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

520383
use crate::bitmap::tests::test_guest_memory_and_region;
521384
use crate::bitmap::AtomicBitmap;
522-
use crate::GuestAddressSpace;
385+
use crate::{Error, GuestAddressSpace, GuestMemory};
523386

524387
use std::io::Write;
525388
use std::mem;
389+
use std::sync::Arc;
526390
#[cfg(feature = "rawfd")]
527391
use std::{fs::File, path::Path};
528392
use vmm_sys_util::tempfile::TempFile;
529393

530-
type GuestMemoryMmap = super::GuestMemoryMmap<()>;
531394
type GuestRegionMmap = super::GuestRegionMmap<()>;
395+
type GuestMemoryMmap = super::GuestRegionCollection<GuestRegionMmap>;
532396
type MmapRegion = super::MmapRegion<()>;
533397

534398
#[test]
@@ -553,9 +417,8 @@ mod tests {
553417
}
554418
assert_eq!(guest_mem.last_addr(), last_addr);
555419
}
556-
for ((region_addr, region_size), mmap) in expected_regions_summary
557-
.iter()
558-
.zip(guest_mem.regions.iter())
420+
for ((region_addr, region_size), mmap) in
421+
expected_regions_summary.iter().zip(guest_mem.iter())
559422
{
560423
assert_eq!(region_addr, &mmap.guest_base);
561424
assert_eq!(region_size, &mmap.mapping.size());
@@ -746,7 +609,7 @@ mod tests {
746609
let regions_summary = [(GuestAddress(0), 100_usize), (GuestAddress(100), 100_usize)];
747610

748611
let guest_mem = GuestMemoryMmap::new();
749-
assert_eq!(guest_mem.regions.len(), 0);
612+
assert_eq!(guest_mem.num_regions(), 0);
750613

751614
check_guest_memory_mmap(new_guest_memory_mmap(&regions_summary), &regions_summary);
752615

@@ -1084,8 +947,10 @@ mod tests {
1084947
.map(|x| (x.0, x.1))
1085948
.eq(iterated_regions.iter().copied()));
1086949

1087-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1088-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
950+
let mmap_regions = gm.iter().collect::<Vec<_>>();
951+
952+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
953+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1089954
}
1090955

1091956
#[test]
@@ -1113,8 +978,10 @@ mod tests {
1113978
.map(|x| (x.0, x.1))
1114979
.eq(iterated_regions.iter().copied()));
1115980

1116-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1117-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
981+
let mmap_regions = gm.iter().collect::<Vec<_>>();
982+
983+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
984+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1118985
}
1119986

1120987
#[test]
@@ -1223,11 +1090,13 @@ mod tests {
12231090
assert_eq!(mem_orig.num_regions(), 2);
12241091
assert_eq!(gm.num_regions(), 5);
12251092

1226-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1227-
assert_eq!(gm.regions[1].start_addr(), GuestAddress(0x4000));
1228-
assert_eq!(gm.regions[2].start_addr(), GuestAddress(0x8000));
1229-
assert_eq!(gm.regions[3].start_addr(), GuestAddress(0xc000));
1230-
assert_eq!(gm.regions[4].start_addr(), GuestAddress(0x10_0000));
1093+
let regions = gm.iter().collect::<Vec<_>>();
1094+
1095+
assert_eq!(regions[0].start_addr(), GuestAddress(0x0000));
1096+
assert_eq!(regions[1].start_addr(), GuestAddress(0x4000));
1097+
assert_eq!(regions[2].start_addr(), GuestAddress(0x8000));
1098+
assert_eq!(regions[3].start_addr(), GuestAddress(0xc000));
1099+
assert_eq!(regions[4].start_addr(), GuestAddress(0x10_0000));
12311100
}
12321101

12331102
#[test]
@@ -1248,7 +1117,7 @@ mod tests {
12481117
assert_eq!(mem_orig.num_regions(), 2);
12491118
assert_eq!(gm.num_regions(), 1);
12501119

1251-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1120+
assert_eq!(gm.iter().next().unwrap().start_addr(), GuestAddress(0x0000));
12521121
assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
12531122
}
12541123

0 commit comments

Comments
 (0)