Redo segment with Arc rather than creating SegmentHeadMeta

This commit is contained in:
Zhang Junyang
2024-06-03 11:55:09 +00:00
committed by Tate, Hongliang Tian
parent 3fa3d7f15a
commit 232e62b053
2 changed files with 55 additions and 54 deletions

View File

@ -1,15 +1,12 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use alloc::sync::Arc;
use core::ops::Range; use core::ops::Range;
use super::Frame; use super::Frame;
use crate::{ use crate::{
mm::{ mm::{
page::{ page::{meta::FrameMeta, Page},
allocator,
meta::{PageMeta, PageUsage, SegmentHeadMeta},
Page,
},
HasPaddr, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE, HasPaddr, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE,
}, },
Error, Result, Error, Result,
@ -34,10 +31,33 @@ use crate::{
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Segment { pub struct Segment {
head_page: Page<SegmentHeadMeta>, inner: Arc<SegmentInner>,
range: Range<usize>, range: Range<usize>,
} }
/// This behaves like a `[Frame]` that owns a list of frame handles.
///
/// The ownership is acheived by the reference counting mechanism of
/// frames. When constructing a `SegmentInner`, the frame handles are
/// forgotten. When dropping a `SegmentInner`, the frame handles are
/// restored and dropped.
#[derive(Debug)]
struct SegmentInner {
start: Paddr,
nframes: usize,
}
impl Drop for SegmentInner {
fn drop(&mut self) {
for i in 0..self.nframes {
let pa_i = self.start + i * PAGE_SIZE;
// SAFETY: for each page there would be a forgotten handle
// when creating the `SegmentInner` object.
drop(unsafe { Page::<FrameMeta>::from_raw(pa_i) });
}
}
}
impl HasPaddr for Segment { impl HasPaddr for Segment {
fn paddr(&self) -> Paddr { fn paddr(&self) -> Paddr {
self.start_paddr() self.start_paddr()
@ -53,10 +73,16 @@ impl Segment {
/// The given range of page frames must not have been allocated before, /// The given range of page frames must not have been allocated before,
/// as part of either a `Frame` or `Segment`. /// as part of either a `Frame` or `Segment`.
pub(crate) unsafe fn new(paddr: Paddr, nframes: usize) -> Self { pub(crate) unsafe fn new(paddr: Paddr, nframes: usize) -> Self {
let mut head = Page::<SegmentHeadMeta>::from_unused(paddr); for i in 0..nframes {
head.meta_mut().seg_len = (nframes * PAGE_SIZE) as u64; let pa_i = paddr + i * PAGE_SIZE;
let page = Page::<FrameMeta>::from_unused(pa_i);
core::mem::forget(page);
}
Self { Self {
head_page: head, inner: Arc::new(SegmentInner {
start: paddr,
nframes,
}),
range: 0..nframes, range: 0..nframes,
} }
} }
@ -73,7 +99,7 @@ impl Segment {
assert!(!adj_range.is_empty() && adj_range.end <= orig_range.end); assert!(!adj_range.is_empty() && adj_range.end <= orig_range.end);
Self { Self {
head_page: self.head_page.clone(), inner: self.inner.clone(),
range: adj_range, range: adj_range,
} }
} }
@ -99,7 +125,7 @@ impl Segment {
} }
fn start_frame_index(&self) -> usize { fn start_frame_index(&self) -> usize {
self.head_page.paddr() / PAGE_SIZE + self.range.start self.inner.start / PAGE_SIZE + self.range.start
} }
pub fn as_ptr(&self) -> *const u8 { pub fn as_ptr(&self) -> *const u8 {
@ -149,20 +175,15 @@ impl VmIo for Segment {
} }
} }
impl PageMeta for SegmentHeadMeta {
const USAGE: PageUsage = PageUsage::SegmentHead;
fn on_drop(page: &mut Page<Self>) {
let nframes = page.meta().seg_len as usize / PAGE_SIZE;
let start_index = page.paddr() / PAGE_SIZE;
unsafe { allocator::dealloc(start_index, nframes) };
}
}
impl From<Frame> for Segment { impl From<Frame> for Segment {
fn from(frame: Frame) -> Self { fn from(frame: Frame) -> Self {
let paddr = frame.paddr();
core::mem::forget(frame);
Self { Self {
head_page: frame.page.into(), inner: Arc::new(SegmentInner {
start: paddr,
nframes: 1,
}),
range: 0..1, range: 0..1,
} }
} }

View File

@ -70,8 +70,6 @@ pub enum PageUsage {
/// The page is used as a frame, i.e., a page of untyped memory. /// The page is used as a frame, i.e., a page of untyped memory.
Frame = 32, Frame = 32,
/// The page is used as the head frame in a segment.
SegmentHead = 33,
/// The page is used by a page table. /// The page is used by a page table.
PageTable = 64, PageTable = 64,
@ -85,7 +83,11 @@ pub enum PageUsage {
pub(in crate::mm) struct MetaSlot { pub(in crate::mm) struct MetaSlot {
/// The metadata of the page. /// The metadata of the page.
/// ///
/// The implementation may cast a `*const MetaSlot` to a `*const PageMeta`. /// It is placed at the beginning of a slot because:
/// - the implementation can simply cast a `*const MetaSlot`
/// to a `*const PageMeta` for manipulation;
/// - the subsequent fields can utilize the end padding of the
/// the inner union to save space.
_inner: MetaSlotInner, _inner: MetaSlotInner,
/// To store [`PageUsage`]. /// To store [`PageUsage`].
pub(super) usage: AtomicU8, pub(super) usage: AtomicU8,
@ -94,7 +96,6 @@ pub(in crate::mm) struct MetaSlot {
pub(super) union MetaSlotInner { pub(super) union MetaSlotInner {
frame: ManuallyDrop<FrameMeta>, frame: ManuallyDrop<FrameMeta>,
seg_head: ManuallyDrop<SegmentHeadMeta>,
// Make sure the the generic parameters don't effect the memory layout. // Make sure the the generic parameters don't effect the memory layout.
pt: ManuallyDrop<PageTablePageMeta<PageTableEntry, PagingConsts>>, pt: ManuallyDrop<PageTablePageMeta<PageTableEntry, PagingConsts>>,
} }
@ -131,37 +132,16 @@ use private::Sealed;
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct FrameMeta {} pub struct FrameMeta {
// If not doing so, the page table metadata would fit
// in the front padding of meta slot and make it 12 bytes.
// We make it 16 bytes. Further usage of frame metadata
// is welcome to exploit this space.
_unused_for_layout_padding: [u8; 8],
}
impl Sealed for FrameMeta {} impl Sealed for FrameMeta {}
#[derive(Debug, Default)]
#[repr(C)]
pub struct SegmentHeadMeta {
/// Length of the segment in bytes.
pub(in crate::mm) seg_len: u64,
}
impl Sealed for SegmentHeadMeta {}
impl From<Page<FrameMeta>> for Page<SegmentHeadMeta> {
fn from(page: Page<FrameMeta>) -> Self {
// FIXME: I intended to prevent a page simultaneously managed by a segment handle
// and a frame handle. However, `Vmo` holds a frame handle while block IO needs a
// segment handle from the same page.
// A segment cannot be mapped. So we have to introduce this enforcement soon:
// assert_eq!(page.count(), 1);
unsafe {
let mut head = Page::<SegmentHeadMeta>::from_raw(page.into_raw());
(*head.ptr)
.usage
.store(PageUsage::SegmentHead as u8, Ordering::Relaxed);
head.meta_mut().seg_len = PAGE_SIZE as u64;
head
}
}
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct PageTablePageMeta<E: PageTableEntryTrait, C: PagingConstsTrait> pub struct PageTablePageMeta<E: PageTableEntryTrait, C: PagingConstsTrait>