-
-
Notifications
You must be signed in to change notification settings - Fork 173
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
Frame allocator changes #1004
Frame allocator changes #1004
Conversation
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 is just a partial review so you can get started addressing some of my comments without having to wait too long for more feedback.
My main concern is that the term UnmappedFrames
or Frames<{FrameState::Unmapped}>
is misleading, or at the very least, quite easy for readers to misunderstand. It makes it sound like those frames were previously mapped and we just unmapped them; in fact, that's how the term has been used thus far, e.g., in the page_table_entry
crate. I'd be interested to hear your thoughts on this; perhaps we can brainstorm another term.
Similarly, there isn't a FrameState
variant that differentiates between "free" (un-allocated) and "unmapped" (allocated). I find that to be confusing, as one would expect there to be a series of changes in state when going from Mapped --> Unmapped --> Free.
Another minor concern is that Frames<{FrameState::Unmapped}>
is ugly to read and definitely hard for newcomers to understand, especially considering that that const enum variant syntax isn't even stable. Let's define typedef aliases for these states and use them everywhere, including within the frame allocator itself.
- Merged
Chunk
andAllocatedFrames
into a single typeFrames
with two states: Unmapped and Mapped. The frame allocator is responsible for make sure aFrames
object has no overlap.
This is generally fine. It's a bit weird that "chunk" is still used prolifically throughout the frame allocator, but I see that you did that on purpose to minimize changes. We can always refactor that later.
- Created a
Region
type used just for bookkeeping.
Nice, I like this.
- Changed the core allocation functions to remove
Frames
objects from the free list before allocating from it (since we can no longer clone aFrames
).
This is inefficient, right? In my mind we should be able to avoid this, since we only need to split it rather than clone it... right?
- For code local to the frame allocator, I changed all references to
AllocatedFrames
toUnmappedFrames
, but for all public functions I kept theAllocatedFrames
terminology.
Sure, fine for now I guess. I'd still like to decide on one term or typedef alias that we can use everywhere, as I said above.
Questions:
- Can we combine
PhysicalMemoryRegion
andRegion
? They contain the same information, butRegion
has additional trait implementations.
Yep, good idea! Let's use the term PhysicalMemoryRegion
since it's much more descriptive than Region
.
- I've added comments in the code for a few specific questions.
Thanks, I responded to them.
In the original design, a clone of the chosen Chunk and the reference to the Chunk in the rb-tree would be passed to the Also, I did consider the design where we split/ merged the chunk while it's still stored in the tree as that could be useful when merging contiguous Though, rb-tree already has functions like |
ah, oops -- i made a change to the page allocator to use I just didn't apply that to the frame allocator yet, so I was mis-remembering what the Drop impl of Anyway, take a look at the Drop implementation for |
Can we move the various new functions from |
New Changes:
|
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.
Based on our slack discussion, let's revert back to using replace_with()
until we have confirmation from intrusive-rs
maintainers that adding a get_mut()
cursor API is okay/sound.
I love the new naming conventions in the frame allocator, they're much clearer! Nice. (I'm referring to things like UnmappedFrames
, FreeFrames
instead of Chunk
, PhysicalMemoryRegion
, etc.
PhysicalMemoryRegion
and its docs are perfectly done, very nice!
One thing about your comment:
- changed the name of
page_table_entry::UnmappedFrames
topage_table_entry::UnmappedFramesInfo
sinceUnmappedFrames
is now a typestate. Now the call back creates anUnmappedFrames
fromUnmappedFramesInfo
Agreed on the need for this name change; however, let's go with something like UnmappedFrameRange
instead of "info" because "info" implies it's some kind of contextual metadata or something, not the actual frames that were unmapped.
Note that I haven't yet deeply reviewed the changes to the internal frame allocator logic itself, i.e., find_specific_chunk()
, find_any_chunk()
, allocate_from_chosen_chunk()
, etc.
I'm still not a huge fan of the redesign regarding allocate_from_chosen_chunk()
in which you always remove a chunk from the list and then re-add it.... I know we previously discussed this briefly during a meeting, but I can't remember what the resolution was.
We can re-discuss this again once your changes to remove get_mut()
usage are in. At that point, I will do a deep review of the actual logic changes in frame allocation, and hopefully we can go through them together in person to speed up my understanding of the changes.
Frames documentation Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Co-authored-by: Kevin Boos <[email protected]>
Thanks, looks good. I can confirm that everything except the changes to the internal frame allocation logic are approved now. I'll review the inner details of the frame allocation logic changes soon. |
(Also i made a few minor changes here and there, make sure to pull those down before you push any other changes) |
Thanks for the review. lmk if you would like to go through those changes together over zoom. |
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.
Full review of internal logic is complete. I left some comments.
There are still some more efficiency improvements that can be made, but I didn't want to overburden you with too many nitpicky comments. I don't think we should bother addressing them until after the verification-related changes are merged in, since that will likely change the code structure even further.
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.
woot, finally made it! The first step to pushing verified code up to the mainline!
Thanks very much! 🎉
frames: self.frames.clone(), | ||
}; | ||
let frames = core::mem::replace(&mut self.frames, FrameRange::empty()); | ||
let free_frames: FreeFrames = Frames { typ: self.typ, frames }; | ||
|
||
let mut list = if free_frames.typ == MemoryRegionType::Reserved { |
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 is fine for now, but in a future PR we should log an error and return early if we encounter an Unknown
type here.
* A single type `Frames` is now used to represent all physical memory frames. * Each `Frames` object is globally unique, and ownership of one represents the exclusive capability to access those frames, e.g., map pages to them. * The `Frames` struct is parameterized with a const generic enum that determines which state it is in, one of four `memory_structs::MemoryState`s: 1. Free: the range of frames is free and is owned by the frame allocator. * `Frames<{MemoryState::Free}>` is type aliased to `FreeFrames`. 2. Allocated: the range of frames has been allocated, and is owned by another entity outside of the frame allocator. * `Frames<{MemoryState::Allocated}>` is type aliased to `AllocatedFrames`, which replaces the previous struct of the same name. 3. Mapped: the range of frames has been mapped by a range of virtual pages. * `Frames<{MemoryState::Mapped}>` is type aliased to `MappedFrames`, which is not yet used in the Theseus codebase. 4. Unmapped: the range of frames has just been unmapped by a range of virtual pages, but has yet to be returned to the frame allocator. * `Frames<{MemoryState::Unmapped}>` is type aliased to `UnmappedFrames`, which is used as an intermediary step before transitioning back into `AllocatedFrames`. * See the documentation of `Frames` for more info on state transitions: (Free) <---> (Allocated) --> (Mapped) --> (Unmapped) --> (Allocated) <---> (Free) * `FreeFrames` is used in favor of `Chunk`. Note that the term "chunk" still appears in the code in order to minimize the sheer volume of tiny changes. * Added a few new APIs to frame-related types, mostly for convenience: `split_at`, `split_range`, `contains_range`. * Combined the `PhysicalMemoryRegion` and `Region` into a single type used across the entire frame allocator. * The core logic of the frame allocator has been changed to accommodate the new `Frames` type, which is a verified "true linear" type that cannot be cloned or have its inner fields mutated. * The entire point of this redesigns is to make the frame allocator amenable to formal verification based on typestate analysis combined with Prusti-verifiable pre- and post-conditions for key functions. * Actual verification code and proofs of frame allocation correctness are coming soon in future PRs. Co-authored-by: Kevin Boos <[email protected]> 0dd9dc6
…1004) * A single type `Frames` is now used to represent all physical memory frames. * Each `Frames` object is globally unique, and ownership of one represents the exclusive capability to access those frames, e.g., map pages to them. * The `Frames` struct is parameterized with a const generic enum that determines which state it is in, one of four `memory_structs::MemoryState`s: 1. Free: the range of frames is free and is owned by the frame allocator. * `Frames<{MemoryState::Free}>` is type aliased to `FreeFrames`. 2. Allocated: the range of frames has been allocated, and is owned by another entity outside of the frame allocator. * `Frames<{MemoryState::Allocated}>` is type aliased to `AllocatedFrames`, which replaces the previous struct of the same name. 3. Mapped: the range of frames has been mapped by a range of virtual pages. * `Frames<{MemoryState::Mapped}>` is type aliased to `MappedFrames`, which is not yet used in the Theseus codebase. 4. Unmapped: the range of frames has just been unmapped by a range of virtual pages, but has yet to be returned to the frame allocator. * `Frames<{MemoryState::Unmapped}>` is type aliased to `UnmappedFrames`, which is used as an intermediary step before transitioning back into `AllocatedFrames`. * See the documentation of `Frames` for more info on state transitions: (Free) <---> (Allocated) --> (Mapped) --> (Unmapped) --> (Allocated) <---> (Free) * `FreeFrames` is used in favor of `Chunk`. Note that the term "chunk" still appears in the code in order to minimize the sheer volume of tiny changes. * Added a few new APIs to frame-related types, mostly for convenience: `split_at`, `split_range`, `contains_range`. * Combined the `PhysicalMemoryRegion` and `Region` into a single type used across the entire frame allocator. * The core logic of the frame allocator has been changed to accommodate the new `Frames` type, which is a verified "true linear" type that cannot be cloned or have its inner fields mutated. * The entire point of this redesigns is to make the frame allocator amenable to formal verification based on typestate analysis combined with Prusti-verifiable pre- and post-conditions for key functions. * Actual verification code and proofs of frame allocation correctness are coming soon in future PRs. Co-authored-by: Kevin Boos <[email protected]> 0dd9dc6
…1004) * A single type `Frames` is now used to represent all physical memory frames. * Each `Frames` object is globally unique, and ownership of one represents the exclusive capability to access those frames, e.g., map pages to them. * The `Frames` struct is parameterized with a const generic enum that determines which state it is in, one of four `memory_structs::MemoryState`s: 1. Free: the range of frames is free and is owned by the frame allocator. * `Frames<{MemoryState::Free}>` is type aliased to `FreeFrames`. 2. Allocated: the range of frames has been allocated, and is owned by another entity outside of the frame allocator. * `Frames<{MemoryState::Allocated}>` is type aliased to `AllocatedFrames`, which replaces the previous struct of the same name. 3. Mapped: the range of frames has been mapped by a range of virtual pages. * `Frames<{MemoryState::Mapped}>` is type aliased to `MappedFrames`, which is not yet used in the Theseus codebase. 4. Unmapped: the range of frames has just been unmapped by a range of virtual pages, but has yet to be returned to the frame allocator. * `Frames<{MemoryState::Unmapped}>` is type aliased to `UnmappedFrames`, which is used as an intermediary step before transitioning back into `AllocatedFrames`. * See the documentation of `Frames` for more info on state transitions: (Free) <---> (Allocated) --> (Mapped) --> (Unmapped) --> (Allocated) <---> (Free) * `FreeFrames` is used in favor of `Chunk`. Note that the term "chunk" still appears in the code in order to minimize the sheer volume of tiny changes. * Added a few new APIs to frame-related types, mostly for convenience: `split_at`, `split_range`, `contains_range`. * Combined the `PhysicalMemoryRegion` and `Region` into a single type used across the entire frame allocator. * The core logic of the frame allocator has been changed to accommodate the new `Frames` type, which is a verified "true linear" type that cannot be cloned or have its inner fields mutated. * The entire point of this redesigns is to make the frame allocator amenable to formal verification based on typestate analysis combined with Prusti-verifiable pre- and post-conditions for key functions. * Actual verification code and proofs of frame allocation correctness are coming soon in future PRs. Co-authored-by: Kevin Boos <[email protected]>
Chunk
andAllocatedFrames
into a single typeFrames
with two states: Unmapped and Mapped. The frame allocator is responsible for make sure aFrames
object has no overlap.Region
type used just for bookkeeping.Frames
objects from the free list before allocating from it (since we can no longer clone aFrames
).AllocatedFrames
toUnmappedFrames
, but for all public functions I kept theAllocatedFrames
terminology.Questions:
PhysicalMemoryRegion
andRegion
? They contain the same information, butRegion
has additional trait implementations.