Skip to content

Commit 037f13d

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 ac74aea commit 037f13d

File tree

4 files changed

+190
-158
lines changed

4 files changed

+190
-158
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 & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,13 @@ use std::borrow::Borrow;
1616
use std::ops::Deref;
1717
use std::result;
1818
use std::sync::atomic::Ordering;
19-
use std::sync::Arc;
2019

2120
use crate::address::Address;
2221
use crate::bitmap::{Bitmap, BS};
23-
use crate::guest_memory::{
24-
self, FileOffset, GuestAddress, GuestMemory, GuestUsize, MemoryRegionAddress,
25-
};
22+
use crate::guest_memory::{self, FileOffset, GuestAddress, GuestUsize, MemoryRegionAddress};
2623
use crate::region::GuestMemoryRegion;
2724
use crate::volatile_memory::{VolatileMemory, VolatileSlice};
28-
use crate::{AtomicAccess, Bytes, ReadVolatile, WriteVolatile};
25+
use crate::{AtomicAccess, Bytes, Error, GuestRegionCollection, ReadVolatile, WriteVolatile};
2926

3027
// re-export for backward compat, as the trait used to be defined in mmap.rs
3128
pub use crate::bitmap::NewBitmap;
@@ -50,26 +47,6 @@ pub use std::io::Error as MmapRegionError;
5047
#[cfg(target_family = "windows")]
5148
pub use windows::MmapRegion;
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-
}
7350

7451
/// [`GuestMemoryRegion`](trait.GuestMemoryRegion.html) implementation that mmaps the guest's
7552
/// memory region in the current process.
@@ -339,17 +316,9 @@ impl<B: Bitmap> GuestMemoryRegion for GuestRegionMmap<B> {
339316
/// Represents the entire physical memory of the guest by tracking all its memory regions.
340317
/// Each region is an instance of `GuestRegionMmap`, being backed by a mapping in the
341318
/// virtual address space of the calling process.
342-
#[derive(Clone, Debug, Default)]
343-
pub struct GuestMemoryMmap<B = ()> {
344-
regions: Vec<Arc<GuestRegionMmap<B>>>,
345-
}
319+
pub type GuestMemoryMmap<B = ()> = GuestRegionCollection<GuestRegionMmap<B>>;
346320

347321
impl<B: NewBitmap> GuestMemoryMmap<B> {
348-
/// Creates an empty `GuestMemoryMmap` instance.
349-
pub fn new() -> Self {
350-
Self::default()
351-
}
352-
353322
/// Creates a container and allocates anonymous memory for guest memory regions.
354323
///
355324
/// Valid memory regions are specified as a slice of (Address, Size) tuples sorted by Address.
@@ -377,111 +346,6 @@ impl<B: NewBitmap> GuestMemoryMmap<B> {
377346
}
378347
}
379348

380-
impl<B: Bitmap> GuestMemoryMmap<B> {
381-
/// Creates a new `GuestMemoryMmap` from a vector of regions.
382-
///
383-
/// # Arguments
384-
///
385-
/// * `regions` - The vector of regions.
386-
/// The regions shouldn't overlap and they should be sorted
387-
/// by the starting address.
388-
pub fn from_regions(mut regions: Vec<GuestRegionMmap<B>>) -> result::Result<Self, Error> {
389-
Self::from_arc_regions(regions.drain(..).map(Arc::new).collect())
390-
}
391-
392-
/// Creates a new `GuestMemoryMmap` from a vector of Arc regions.
393-
///
394-
/// Similar to the constructor `from_regions()` as it returns a
395-
/// `GuestMemoryMmap`. The need for this constructor is to provide a way for
396-
/// consumer of this API to create a new `GuestMemoryMmap` based on existing
397-
/// regions coming from an existing `GuestMemoryMmap` instance.
398-
///
399-
/// # Arguments
400-
///
401-
/// * `regions` - The vector of `Arc` regions.
402-
/// The regions shouldn't overlap and they should be sorted
403-
/// by the starting address.
404-
pub fn from_arc_regions(regions: Vec<Arc<GuestRegionMmap<B>>>) -> result::Result<Self, Error> {
405-
if regions.is_empty() {
406-
return Err(Error::NoMemoryRegion);
407-
}
408-
409-
for window in regions.windows(2) {
410-
let prev = &window[0];
411-
let next = &window[1];
412-
413-
if prev.start_addr() > next.start_addr() {
414-
return Err(Error::UnsortedMemoryRegions);
415-
}
416-
417-
if prev.last_addr() >= next.start_addr() {
418-
return Err(Error::MemoryRegionOverlap);
419-
}
420-
}
421-
422-
Ok(Self { regions })
423-
}
424-
425-
/// Insert a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`.
426-
///
427-
/// # Arguments
428-
/// * `region`: the memory region to insert into the guest memory object.
429-
pub fn insert_region(
430-
&self,
431-
region: Arc<GuestRegionMmap<B>>,
432-
) -> result::Result<GuestMemoryMmap<B>, Error> {
433-
let mut regions = self.regions.clone();
434-
regions.push(region);
435-
regions.sort_by_key(|x| x.start_addr());
436-
437-
Self::from_arc_regions(regions)
438-
}
439-
440-
/// Remove a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`
441-
/// on success, together with the removed region.
442-
///
443-
/// # Arguments
444-
/// * `base`: base address of the region to be removed
445-
/// * `size`: size of the region to be removed
446-
pub fn remove_region(
447-
&self,
448-
base: GuestAddress,
449-
size: GuestUsize,
450-
) -> result::Result<(GuestMemoryMmap<B>, Arc<GuestRegionMmap<B>>), Error> {
451-
if let Ok(region_index) = self.regions.binary_search_by_key(&base, |x| x.start_addr()) {
452-
if self.regions.get(region_index).unwrap().mapping.size() as GuestUsize == size {
453-
let mut regions = self.regions.clone();
454-
let region = regions.remove(region_index);
455-
return Ok((Self { regions }, region));
456-
}
457-
}
458-
459-
Err(Error::InvalidGuestRegion)
460-
}
461-
}
462-
463-
impl<B: Bitmap + 'static> GuestMemory for GuestMemoryMmap<B> {
464-
type R = GuestRegionMmap<B>;
465-
466-
fn num_regions(&self) -> usize {
467-
self.regions.len()
468-
}
469-
470-
fn find_region(&self, addr: GuestAddress) -> Option<&GuestRegionMmap<B>> {
471-
let index = match self.regions.binary_search_by_key(&addr, |x| x.start_addr()) {
472-
Ok(x) => Some(x),
473-
// Within the closest region with starting address < addr
474-
Err(x) if (x > 0 && addr <= self.regions[x - 1].last_addr()) => Some(x - 1),
475-
_ => None,
476-
};
477-
index.map(|x| self.regions[x].as_ref())
478-
}
479-
480-
fn iter(&self) -> impl Iterator<Item = &Self::R> {
481-
self.regions.iter().map(AsRef::as_ref)
482-
}
483-
}
484-
485349
#[cfg(test)]
486350
mod tests {
487351
#![allow(clippy::undocumented_unsafe_blocks)]
@@ -491,16 +355,17 @@ mod tests {
491355

492356
use crate::bitmap::tests::test_guest_memory_and_region;
493357
use crate::bitmap::AtomicBitmap;
494-
use crate::GuestAddressSpace;
358+
use crate::{Error, GuestAddressSpace, GuestMemory};
495359

496360
use std::io::Write;
497361
use std::mem;
362+
use std::sync::Arc;
498363
#[cfg(feature = "rawfd")]
499364
use std::{fs::File, path::Path};
500365
use vmm_sys_util::tempfile::TempFile;
501366

502-
type GuestMemoryMmap = super::GuestMemoryMmap<()>;
503367
type GuestRegionMmap = super::GuestRegionMmap<()>;
368+
type GuestMemoryMmap = super::GuestRegionCollection<GuestRegionMmap>;
504369
type MmapRegion = super::MmapRegion<()>;
505370

506371
#[test]
@@ -525,9 +390,8 @@ mod tests {
525390
}
526391
assert_eq!(guest_mem.last_addr(), last_addr);
527392
}
528-
for ((region_addr, region_size), mmap) in expected_regions_summary
529-
.iter()
530-
.zip(guest_mem.regions.iter())
393+
for ((region_addr, region_size), mmap) in
394+
expected_regions_summary.iter().zip(guest_mem.iter())
531395
{
532396
assert_eq!(region_addr, &mmap.guest_base);
533397
assert_eq!(region_size, &mmap.mapping.size());
@@ -718,7 +582,7 @@ mod tests {
718582
let regions_summary = [(GuestAddress(0), 100_usize), (GuestAddress(100), 100_usize)];
719583

720584
let guest_mem = GuestMemoryMmap::new();
721-
assert_eq!(guest_mem.regions.len(), 0);
585+
assert_eq!(guest_mem.num_regions(), 0);
722586

723587
check_guest_memory_mmap(new_guest_memory_mmap(&regions_summary), &regions_summary);
724588

@@ -1056,8 +920,10 @@ mod tests {
1056920
.map(|x| (x.0, x.1))
1057921
.eq(iterated_regions.iter().copied()));
1058922

1059-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1060-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
923+
let mmap_regions = gm.iter().collect::<Vec<_>>();
924+
925+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
926+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1061927
}
1062928

1063929
#[test]
@@ -1085,8 +951,10 @@ mod tests {
1085951
.map(|x| (x.0, x.1))
1086952
.eq(iterated_regions.iter().copied()));
1087953

1088-
assert_eq!(gm.regions[0].guest_base, regions[0].0);
1089-
assert_eq!(gm.regions[1].guest_base, regions[1].0);
954+
let mmap_regions = gm.iter().collect::<Vec<_>>();
955+
956+
assert_eq!(mmap_regions[0].guest_base, regions[0].0);
957+
assert_eq!(mmap_regions[1].guest_base, regions[1].0);
1090958
}
1091959

1092960
#[test]
@@ -1195,11 +1063,13 @@ mod tests {
11951063
assert_eq!(mem_orig.num_regions(), 2);
11961064
assert_eq!(gm.num_regions(), 5);
11971065

1198-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1199-
assert_eq!(gm.regions[1].start_addr(), GuestAddress(0x4000));
1200-
assert_eq!(gm.regions[2].start_addr(), GuestAddress(0x8000));
1201-
assert_eq!(gm.regions[3].start_addr(), GuestAddress(0xc000));
1202-
assert_eq!(gm.regions[4].start_addr(), GuestAddress(0x10_0000));
1066+
let regions = gm.iter().collect::<Vec<_>>();
1067+
1068+
assert_eq!(regions[0].start_addr(), GuestAddress(0x0000));
1069+
assert_eq!(regions[1].start_addr(), GuestAddress(0x4000));
1070+
assert_eq!(regions[2].start_addr(), GuestAddress(0x8000));
1071+
assert_eq!(regions[3].start_addr(), GuestAddress(0xc000));
1072+
assert_eq!(regions[4].start_addr(), GuestAddress(0x10_0000));
12031073
}
12041074

12051075
#[test]
@@ -1220,7 +1090,7 @@ mod tests {
12201090
assert_eq!(mem_orig.num_regions(), 2);
12211091
assert_eq!(gm.num_regions(), 1);
12221092

1223-
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1093+
assert_eq!(gm.iter().next().unwrap().start_addr(), GuestAddress(0x0000));
12241094
assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
12251095
}
12261096

0 commit comments

Comments
 (0)