mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
Redo segment with Arc
rather than creating SegmentHeadMeta
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
3fa3d7f15a
commit
232e62b053
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
Reference in New Issue
Block a user