Skip to content

Generify parts of mmap.rs #312

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

roypat
Copy link
Member

@roypat roypat commented Feb 10, 2025

Summary of the PR

Mainly, 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.

While we're at it, generalize the impl Bytes for GuestRegionMmap into impl<R: GuestMemoryRegion> Bytes for R, because really that impls didn't actually make use of any specifics of the GuestRegionMmap struct.

This PR is the backward-compatible subset of #317. In that context, it is 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 modules mmap_windows, mmap_xen and mmap_unix exist, since they all define roughly the same types which are then imported by the mmap module without renames). However, short-term is is also a required step for enabling things like #315 without necessarily requiring changes in core vm-memory code.

Requirements

Before submitting your PR, please make sure you addressed the following
requirements:

  • All commits in this PR have Signed-Off-By trailers (with
    git commit -s), and the commit message has max 60 characters for the
    summary and max 75 characters for each description line.
  • All added/changed functionality has a corresponding unit/integration
    test.
  • All added/changed public-facing functionality has entries in the "Upcoming
    Release" section of CHANGELOG.md (if no such section exists, please create one).
  • Any newly added unsafe code is properly documented.

@roypat roypat force-pushed the generic-region-container branch 2 times, most recently from df86175 to c76a6ca Compare February 10, 2025 17:20
@roypat roypat force-pushed the generic-region-container branch from c76a6ca to ae4c4f6 Compare March 17, 2025 11:12
@roypat roypat changed the title Generalize GuestMemoryMmap to arbitrary GuestMemoryRegions Generify parts of mmap.rs Mar 17, 2025
@roypat roypat requested review from ShadowCurse and andreeaflorescu and removed request for ShadowCurse March 17, 2025 15:04
ShadowCurse
ShadowCurse previously approved these changes Mar 19, 2025
@roypat roypat force-pushed the generic-region-container branch from ae4c4f6 to 5e4e1d4 Compare March 21, 2025 11:12
@roypat
Copy link
Member Author

roypat commented Mar 27, 2025

Hey @bonzini, since you chimed in over at #321 the other day, any thoughts on this one? :o

@bonzini
Copy link
Member

bonzini commented Mar 27, 2025

While we're at it, generalize the impl Bytes for GuestRegionMmap into impl<R: GuestMemoryRegion> Bytes for R, because really that impls didn't actually make use of any specifics of the GuestRegionMmap struct.

I would need to double check that. IIRC if QEMU was ever going to use vm-memory, which actually could happen now, it needed something custom to handle access to an assigned device's BAR.

@roypat
Copy link
Member Author

roypat commented Mar 27, 2025

While we're at it, generalize the impl Bytes for GuestRegionMmap into impl<R: GuestMemoryRegion> Bytes for R, because really that impls didn't actually make use of any specifics of the GuestRegionMmap struct.

I would need to double check that. IIRC if QEMU was ever going to use vm-memory, which actually could happen now, it needed something custom to handle access to an assigned device's BAR.

Ah, that's good to know, thanks! I can rework it, so that an additional empty marker trait is required to be implemented, e.g. GuestMemoryRegionBytes: GuestMemoryRegion and then only have impl<R: GuestMemoryRegionBytes> Bytes for R { ... }?

@roypat roypat force-pushed the generic-region-container branch from e7d74ea to bc4e643 Compare March 27, 2025 13:49
@roypat
Copy link
Member Author

roypat commented Mar 27, 2025

While we're at it, generalize the impl Bytes for GuestRegionMmap into impl<R: GuestMemoryRegion> Bytes for R, because really that impls didn't actually make use of any specifics of the GuestRegionMmap struct.

I would need to double check that. IIRC if QEMU was ever going to use vm-memory, which actually could happen now, it needed something custom to handle access to an assigned device's BAR.

Ah, that's good to know, thanks! I can rework it, so that an additional empty marker trait is required to be implemented, e.g. GuestMemoryRegionBytes: GuestMemoryRegion and then only have impl<R: GuestMemoryRegionBytes> Bytes for R { ... }?

Done :)

@bonzini
Copy link
Member

bonzini commented Mar 27, 2025

That doesn't hurt, yes :) I will tell you tomorrow anyway!

roypat added 7 commits April 16, 2025 07:15
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 <[email protected]>
This modules is intended for all functionality that relates to
contiguous regions of guest memory. This differentiates it from
`guest_memory`, as that is about a holistic view of guest memory, and
from `mmap`, which is specifically about guest memory regions backed by
mmap VMAs.

Signed-off-by: Patrick Roy <[email protected]>
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]>
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 <[email protected]>
This trait implementation of GuestMemoryRegion for `GuestRegionMmap`does
not actually make use of the specifics of `GuestRegionMmap`, so can be
completely generic in terms of `GuestMemoryRegion`. This allows us to
move it to guest_memory.rs, eliminating one further instance of code
depending on exactly one of mmap_unix.rs and mmap_xen.rs being compiled
in.

However, Paolo pointed out that sometimes this default impl might not be
desired, for example QEMU might want some GuestMemoryRegion impl that
represents PCI BARs. So hide this impl behind a marker trait,
GuestMemoryRegionBytes, being implemented.

Replace .unwrap() with error propagation via `?`, as we no longer know
that we are dealing with a specific GuestMemoryRegion impl that always
implements as_volatile_slice().

Signed-off-by: Patrick Roy <[email protected]>
Move some tests that are all about the invariants of
GuestRegionCollection constructors to region.rs, where they can be run
without the need for the backend-mmap feature (by instead using a mock
memory region).

While we're at it, fix these tests calling from_regions twice, but
from_arc_regions never.

Remove some test cases that are superfluous, because since the `regions`
field of `GuestRegionCollection` is private, all construction needs to
go through `from_regions`/`from_arc_regions`, and testing that wrappers
around these functions uphold the invariants of the wrapped functions is
not very useful.

test_memory and create_vec_with_regions were the same test, so
deduplicate while moving to region.rs.

Generally, most of these tests could be moved to region.rs, given
sufficient mocking of the memory region. I've somewhat arbitrarily drawn
the line at "only transfer tests where the mock only needs GuestAddress
and length", which roughly translates to "move tests where we are
testing the default implementations of the GuestMemory and
GuestMemoryRegion traits, which are not overwritten in the mmap-based
implementations". Of course, we could write a mock that implements
actual allocation of memory via std::alloc::alloc, but at that point
we'd be testing the mock more than actual vm-memory code (and start
loosing coverage of the mmap implementations).

Signed-off-by: Patrick Roy <[email protected]>
These tests only test properties of the GuestMemoryAtomic implementation
that are independent of the actual M: GuestMemory being used. So
simplify it to drop the dependency on backend-mmap.

Signed-off-by: Patrick Roy <[email protected]>
@roypat roypat force-pushed the generic-region-container branch from f3ce283 to 04b4509 Compare April 16, 2025 06:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants