-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generalize GuestMemoryMmap to arbitrary GuestMemoryRegions #312
base: main
Are you sure you want to change the base?
Conversation
This function can be default-implemented in terms of `GuestMemory::iter()`. Downstream impls can overwrite this more specialized and efficient versions of course (such as GuestMemoryMmap using a binary search). Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
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 <roypat@amazon.co.uk>
99d1a51
to
df86175
Compare
Some tests that were explicitly testing for error conditions used converted errors to strings to determine whether two errors are the same (by saying they're only the same if their string representation was identical). Replace this with more roboust assertions on `matches!`. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
df86175
to
c76a6ca
Compare
if regions.is_empty() { | ||
return Err(GuestRegionCollectionError::NoMemoryRegion); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really an error to provide no regions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is just moved from mmap.rs without changes. There might be improvements that can be made to the actual API, but that's out of scope here I'd say, because ideally we'd keep backwards compatibility here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
pub fn insert_region( | ||
&self, | ||
region: Arc<R>, | ||
) -> std::result::Result<GuestRegionCollection<R>, GuestRegionCollectionError> { | ||
let mut regions = self.regions.clone(); | ||
regions.push(region); | ||
regions.sort_by_key(|x| x.start_addr()); | ||
|
||
Self::from_arc_regions(regions) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should just take &mut self
and mutate in place. The check for region intersection can be moved into a separate function and used here and in the from_arc_regions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is just moved from mmap.rs without changes. There might be improvements that can be made to the actual API, but that's out of scope here I'd say, because ideally we'd keep backwards compatibility here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
/// * `base`: base address of the region to be removed | ||
/// * `size`: size of the region to be removed | ||
pub fn remove_region( | ||
&self, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, why not &mut self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is just moved from mmap.rs without changes. There might be improvements that can be made to the actual API, but that's out of scope here I'd say, because ideally we'd keep backwards compatibility here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
} | ||
} | ||
|
||
Err(GuestRegionCollectionError::NoMemoryRegion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an error to remove a non existing region? Maybe return type should be (Self, Option<Arc<R>>)
where optional is the removed region if it existed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is just moved from mmap.rs without changes. There might be improvements that can be made to the actual API, but that's out of scope here I'd say, because ideally we'd keep backwards compatibility here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
let index = match self.regions.binary_search_by_key(&addr, |x| x.start_addr()) { | ||
Ok(x) => Some(x), | ||
// Within the closest region with starting address < addr | ||
Err(x) if (x > 0 && addr <= self.regions[x - 1].last_addr()) => Some(x - 1), | ||
_ => None, | ||
}; | ||
index.map(|x| self.regions[x].as_ref()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many regions there can possibly be? I think a simple for loop where we check if address is in the region will be as fast in general case and more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is also just moved from mmap.rs, so I also err'd on the side of keeping things as they are. The default implementation for this trait function indeed just uses a simple loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
@@ -586,6 +587,168 @@ pub trait GuestMemory { | |||
} | |||
} | |||
|
|||
/// Errors that can occur when creating a memory map. | |||
#[derive(Debug, thiserror::Error)] | |||
pub enum GuestRegionCollectionError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole GuestRegionCollection
looks like it can be moved into it's own module. Also maybe rename to just Regions
? I assume there are no other regions other than memory regions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mh, I'd be open to having it in its own module. What should we call it though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just regions.rs
?
Summary of the PR
Add the concept of a
GuestRegionCollection
, which just manages a listof some
GuestMemoryRegion
impls. Functionality wise, it offers thesame implementations as
GuestMemoryMmap
. As a result, turnGuestMemoryMmap
into a type alias forGuestRegionCollection
with afixed
R = GuestRegionMmap
.Long term, this can be a first step towards resolving the incompatibility between the unix and xen features (currently, the code in
mmap.rs
only works if exactly one of the modulesmmap_windows
,mmap_xen
andmmap_unix
exist, since they all define roughly the same types which are then imported by themmap
module without renames)The last commit is only tangentially related, but I ran into it when moving around the error type, and I like having PRs that remove more lines than they add, so I included it here xP
Requirements
Before submitting your PR, please make sure you addressed the following
requirements:
git commit -s
), and the commit message has max 60 characters for thesummary and max 75 characters for each description line.
test.
Release" section of CHANGELOG.md (if no such section exists, please create one).
unsafe
code is properly documented.