mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 03:43:23 +00:00
Remove the concept of child VMOs and clean-up VMO implementations
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9f9169adfe
commit
19184d5c3d
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1757,7 +1757,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "xarray"
|
name = "xarray"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/asterinas/xarray?rev=72a4067#72a4067a65e8f94cfc193f5f19ebc981c1de9de7"
|
source = "git+https://github.com/asterinas/xarray#1dad5d9b74aac30193bd242a97077b4c54933830"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
@ -5,72 +5,14 @@ use core::ops::Range;
|
|||||||
use aster_rights::{Rights, TRights};
|
use aster_rights::{Rights, TRights};
|
||||||
use ostd::mm::{Frame, VmIo};
|
use ostd::mm::{Frame, VmIo};
|
||||||
|
|
||||||
use super::{
|
use super::{CommitFlags, Vmo, VmoRightsOp};
|
||||||
options::{VmoCowChild, VmoSliceChild},
|
|
||||||
CommitFlags, Vmo, VmoChildOptions, VmoRightsOp,
|
|
||||||
};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl Vmo<Rights> {
|
impl Vmo<Rights> {
|
||||||
/// Creates a new slice VMO through a set of VMO child options.
|
/// Commits a page at specific offset
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
|
||||||
/// let child_size = parent.size();
|
|
||||||
/// let child = parent.new_slice_child(0..child_size).alloc().unwrap();
|
|
||||||
/// assert!(child.size() == child_size);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For more details on the available options, see `VmoChildOptions`.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// This method requires the Dup right.
|
|
||||||
///
|
|
||||||
/// The new VMO child will be of the same capability flavor as the parent;
|
|
||||||
/// so are the access rights.
|
|
||||||
pub fn new_slice_child(
|
|
||||||
&self,
|
|
||||||
range: Range<usize>,
|
|
||||||
) -> Result<VmoChildOptions<Rights, VmoSliceChild>> {
|
|
||||||
let dup_self = self.dup()?;
|
|
||||||
Ok(VmoChildOptions::new_slice_rights(dup_self, range))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new COW VMO through a set of VMO child options.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
|
||||||
/// let child_size = 2 * parent.size();
|
|
||||||
/// let child = parent.new_cow_child(0..child_size).alloc().unwrap();
|
|
||||||
/// assert!(child.size() == child_size);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For more details on the available options, see `VmoChildOptions`.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// This method requires the Dup right.
|
|
||||||
///
|
|
||||||
/// The new VMO child will be of the same capability flavor as the parent.
|
|
||||||
/// The child will be given the access rights of the parent
|
|
||||||
/// plus the Write right.
|
|
||||||
pub fn new_cow_child(
|
|
||||||
&self,
|
|
||||||
range: Range<usize>,
|
|
||||||
) -> Result<VmoChildOptions<Rights, VmoCowChild>> {
|
|
||||||
let dup_self = self.dup()?;
|
|
||||||
Ok(VmoChildOptions::new_cow(dup_self, range))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// commit a page at specific offset
|
|
||||||
pub fn commit_page(&self, offset: usize) -> Result<Frame> {
|
pub fn commit_page(&self, offset: usize) -> Result<Frame> {
|
||||||
self.check_rights(Rights::WRITE)?;
|
self.check_rights(Rights::WRITE)?;
|
||||||
self.0.commit_page(offset, false)
|
self.0.commit_page(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits the pages specified in the range (in bytes).
|
/// Commits the pages specified in the range (in bytes).
|
||||||
@ -137,6 +79,29 @@ impl Vmo<Rights> {
|
|||||||
Ok(Self(self.0.clone(), self.1))
|
Ok(Self(self.0.clone(), self.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new VMO that replicates the original capability, initially representing
|
||||||
|
/// the same physical pages.
|
||||||
|
/// Changes to the permissions and commits/replacements of internal pages in the original VMO
|
||||||
|
/// and the new VMO will not affect each other.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Dup right.
|
||||||
|
pub fn dup_independent(&self) -> Result<Self> {
|
||||||
|
self.check_rights(Rights::DUP | Rights::WRITE)?;
|
||||||
|
Ok(Vmo(Arc::new(super::Vmo_::clone(&self.0)), self.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the page at the `page_idx` in the VMO with the input `page`.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Write right.
|
||||||
|
pub fn replace(&self, page: Frame, page_idx: usize) -> Result<()> {
|
||||||
|
self.check_rights(Rights::WRITE)?;
|
||||||
|
self.0.replace(page, page_idx)
|
||||||
|
}
|
||||||
|
|
||||||
/// Restricts the access rights given the mask.
|
/// Restricts the access rights given the mask.
|
||||||
pub fn restrict(mut self, mask: Rights) -> Self {
|
pub fn restrict(mut self, mask: Rights) -> Self {
|
||||||
self.1 |= mask;
|
self.1 |= mask;
|
||||||
|
@ -10,7 +10,7 @@ use core::ops::Range;
|
|||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_rights::Rights;
|
use aster_rights::Rights;
|
||||||
use ostd::{
|
use ostd::{
|
||||||
collections::xarray::{CursorMut, XArray, XMark},
|
collections::xarray::{CursorMut, XArray},
|
||||||
mm::{Frame, FrameAllocOptions, VmReader, VmWriter},
|
mm::{Frame, FrameAllocOptions, VmReader, VmWriter},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,11 +21,9 @@ mod options;
|
|||||||
mod pager;
|
mod pager;
|
||||||
mod static_cap;
|
mod static_cap;
|
||||||
|
|
||||||
pub use options::{VmoChildOptions, VmoOptions};
|
pub use options::VmoOptions;
|
||||||
pub use pager::Pager;
|
pub use pager::Pager;
|
||||||
|
|
||||||
use self::options::ChildType;
|
|
||||||
|
|
||||||
/// Virtual Memory Objects (VMOs) are a type of capability that represents a
|
/// Virtual Memory Objects (VMOs) are a type of capability that represents a
|
||||||
/// range of memory pages.
|
/// range of memory pages.
|
||||||
///
|
///
|
||||||
@ -35,12 +33,6 @@ use self::options::ChildType;
|
|||||||
/// memory pages that it contain.
|
/// memory pages that it contain.
|
||||||
/// * **On-demand paging.** The memory pages of a VMO (except for _contiguous_
|
/// * **On-demand paging.** The memory pages of a VMO (except for _contiguous_
|
||||||
/// VMOs) are allocated lazily when the page is first accessed.
|
/// VMOs) are allocated lazily when the page is first accessed.
|
||||||
/// * **Tree structure.** Given a VMO, one can create a child VMO from it.
|
|
||||||
/// The child VMO can only access a subset of the parent's memory,
|
|
||||||
/// which is a good thing for the perspective of access control.
|
|
||||||
/// * **Copy-on-write (COW).** A child VMO may be created with COW semantics,
|
|
||||||
/// which prevents any writes on the child from affecting the parent
|
|
||||||
/// by duplicating memory pages only upon the first writes.
|
|
||||||
/// * **Access control.** As capabilities, VMOs restrict the
|
/// * **Access control.** As capabilities, VMOs restrict the
|
||||||
/// accessible range of memory and the allowed I/O operations.
|
/// accessible range of memory and the allowed I/O operations.
|
||||||
/// * **Device driver support.** If specified upon creation, VMOs will be
|
/// * **Device driver support.** If specified upon creation, VMOs will be
|
||||||
@ -69,15 +61,13 @@ use self::options::ChildType;
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// For creating root VMOs, see `VmoOptions`.`
|
/// For creating root VMOs, see [`VmoOptions`].
|
||||||
///
|
|
||||||
/// For creating child VMOs, see `VmoChildOptions`.
|
|
||||||
///
|
///
|
||||||
/// # Implementation
|
/// # Implementation
|
||||||
///
|
///
|
||||||
/// `Vmo` provides high-level APIs for address space management by wrapping
|
/// `Vmo` provides high-level APIs for address space management by wrapping
|
||||||
/// around its low-level counterpart `ostd::vm::VmFrames`.
|
/// around its low-level counterpart [`ostd::mm::Frame`].
|
||||||
/// Compared with `VmFrames`,
|
/// Compared with `Frame`,
|
||||||
/// `Vmo` is easier to use (by offering more powerful APIs) and
|
/// `Vmo` is easier to use (by offering more powerful APIs) and
|
||||||
/// harder to misuse (thanks to its nature of being capability).
|
/// harder to misuse (thanks to its nature of being capability).
|
||||||
///
|
///
|
||||||
@ -135,41 +125,31 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks used for the `XArray` in `Vmo_`.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub(super) enum VmoMark {
|
|
||||||
/// Marks used for the VMO's `pages` which is managed by `XArray`.
|
|
||||||
/// The VMO whose `pages` is marked as `CowVmo` may require a Copy-On-Write (COW) operation
|
|
||||||
/// when performing a write action.
|
|
||||||
CowVmo,
|
|
||||||
/// Marks used for the `Frame` stored within the pages marked as `CowVmo`,
|
|
||||||
/// `Frame`s marked as `ExclusivePage` are newly created through the COW mechanism
|
|
||||||
/// and do not require further COW operations.
|
|
||||||
ExclusivePage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<VmoMark> for XMark {
|
|
||||||
fn from(val: VmoMark) -> Self {
|
|
||||||
match val {
|
|
||||||
VmoMark::CowVmo => XMark::Mark0,
|
|
||||||
VmoMark::ExclusivePage => XMark::Mark1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `Pages` is the struct that manages the `Frame`s stored in `Vmo_`.
|
/// `Pages` is the struct that manages the `Frame`s stored in `Vmo_`.
|
||||||
pub(super) enum Pages {
|
pub(super) enum Pages {
|
||||||
/// `Pages` that cannot be resized. This kind of `Pages` will have a constant size.
|
/// `Pages` that cannot be resized. This kind of `Pages` will have a constant size.
|
||||||
Nonresizable(Arc<Mutex<XArray<Frame, VmoMark>>>, usize),
|
Nonresizable(Mutex<XArray<Frame>>, usize),
|
||||||
/// `Pages` that can be resized and have a variable size, and such `Pages` cannot
|
/// `Pages` that can be resized and have a variable size.
|
||||||
/// be shared between different VMOs.
|
Resizable(Mutex<(XArray<Frame>, usize)>),
|
||||||
Resizable(Mutex<(XArray<Frame, VmoMark>, usize)>),
|
}
|
||||||
|
|
||||||
|
impl Clone for Pages {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Nonresizable(_, _) => {
|
||||||
|
self.with(|pages, size| Self::Nonresizable(Mutex::new(pages.clone()), size))
|
||||||
|
}
|
||||||
|
Self::Resizable(_) => {
|
||||||
|
self.with(|pages, size| Self::Resizable(Mutex::new((pages.clone(), size))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pages {
|
impl Pages {
|
||||||
fn with<R, F>(&self, func: F) -> R
|
fn with<R, F>(&self, func: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut XArray<Frame, VmoMark>, usize) -> R,
|
F: FnOnce(&mut XArray<Frame>, usize) -> R,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Self::Nonresizable(pages, size) => func(&mut pages.lock(), *size),
|
Self::Nonresizable(pages, size) => func(&mut pages.lock(), *size),
|
||||||
@ -187,167 +167,92 @@ impl Pages {
|
|||||||
/// 1. File-backed VMO: the VMO backed by a file and resides in the `PageCache`,
|
/// 1. File-backed VMO: the VMO backed by a file and resides in the `PageCache`,
|
||||||
/// which includes a pager to provide it with actual pages.
|
/// which includes a pager to provide it with actual pages.
|
||||||
/// 2. Anonymous VMO: the VMO without a file backup, which does not have a pager.
|
/// 2. Anonymous VMO: the VMO without a file backup, which does not have a pager.
|
||||||
|
#[derive(Clone)]
|
||||||
pub(super) struct Vmo_ {
|
pub(super) struct Vmo_ {
|
||||||
pager: Option<Arc<dyn Pager>>,
|
pager: Option<Arc<dyn Pager>>,
|
||||||
/// Flags
|
/// Flags
|
||||||
flags: VmoFlags,
|
flags: VmoFlags,
|
||||||
/// The offset of the range of pages corresponding to the VMO within `pages`.
|
|
||||||
page_idx_offset: usize,
|
|
||||||
/// The virtual pages where the VMO resides.
|
/// The virtual pages where the VMO resides.
|
||||||
pages: Pages,
|
pages: Pages,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_page(page: &Frame) -> Result<Frame> {
|
|
||||||
let new_page = FrameAllocOptions::new(1).alloc_single()?;
|
|
||||||
new_page.copy_from(page);
|
|
||||||
Ok(new_page)
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Commit Flags.
|
/// Commit Flags.
|
||||||
pub struct CommitFlags: u8 {
|
pub struct CommitFlags: u8 {
|
||||||
/// Set this flag if the page will be written soon.
|
|
||||||
const WILL_WRITE = 1;
|
|
||||||
/// Set this flag if the page will be completely overwritten.
|
/// Set this flag if the page will be completely overwritten.
|
||||||
/// This flag contains the WILL_WRITE flag.
|
/// This flag contains the WILL_WRITE flag.
|
||||||
const WILL_OVERWRITE = 3;
|
const WILL_OVERWRITE = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitFlags {
|
impl CommitFlags {
|
||||||
pub fn will_write(&self) -> bool {
|
|
||||||
self.contains(Self::WILL_WRITE)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn will_overwrite(&self) -> bool {
|
pub fn will_overwrite(&self) -> bool {
|
||||||
self.contains(Self::WILL_OVERWRITE)
|
self.contains(Self::WILL_OVERWRITE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vmo_ {
|
impl Vmo_ {
|
||||||
/// Prepare a new `Frame` for the target index in pages, returning the new page as well as
|
/// Prepares a new `Frame` for the target index in pages, returns this new frame.
|
||||||
/// whether this page needs to be marked as exclusive.
|
fn prepare_page(&self, page_idx: usize) -> Result<Frame> {
|
||||||
///
|
match &self.pager {
|
||||||
/// Based on the type of VMO and the impending operation on the prepared page, there are 3 conditions:
|
None => Ok(FrameAllocOptions::new(1).alloc_single()?),
|
||||||
/// 1. For an Anonymous VMO, provide a new page directly. If the VMO requires copy-on-write (COW),
|
Some(pager) => pager.commit_page(page_idx),
|
||||||
/// the prepared page can be directly set to exclusive.
|
|
||||||
/// 2. For a File-backed VMO that does not need to trigger the COW mechanism,
|
|
||||||
/// obtain a page from the pager directly without the need to be set as exclusive.
|
|
||||||
/// 3. For a File-backed VMO that requires triggering the COW mechanism, obtain a page
|
|
||||||
/// from the pager and then copy it. This page can be set as exclusive.
|
|
||||||
fn prepare_page(
|
|
||||||
&self,
|
|
||||||
page_idx: usize,
|
|
||||||
is_cow_vmo: bool,
|
|
||||||
commit_flags: CommitFlags,
|
|
||||||
) -> Result<(Frame, bool)> {
|
|
||||||
let (page, should_mark_exclusive) = match &self.pager {
|
|
||||||
None => {
|
|
||||||
// Condition 1. The new anonymous page only need to be marked as `ExclusivePage`
|
|
||||||
// when current VMO is a cow VMO, otherwise this mark is meaningless.
|
|
||||||
(FrameAllocOptions::new(1).alloc_single()?, is_cow_vmo)
|
|
||||||
}
|
}
|
||||||
Some(pager) => {
|
|
||||||
let page = pager.commit_page(page_idx)?;
|
|
||||||
// The prerequisite for triggering the COW mechanism here is that the current
|
|
||||||
// VMO requires COW and the prepared page is about to undergo a write operation.
|
|
||||||
// At this point, the `Frame` obtained from the pager needs to be cloned to
|
|
||||||
// avoid subsequent modifications affecting the content of the `Frame` in the pager.
|
|
||||||
let trigger_cow = is_cow_vmo && commit_flags.will_write();
|
|
||||||
if trigger_cow {
|
|
||||||
// Condition 3.
|
|
||||||
(clone_page(&page)?, true)
|
|
||||||
} else {
|
|
||||||
// Condition 2.
|
|
||||||
(page, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok((page, should_mark_exclusive))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare a new `Frame` for the target index in pages, returning the new page.
|
/// Prepares a new `Frame` for the target index in the VMO, returns this new frame.
|
||||||
/// This function is only used when the new `Frame` will be completely overwritten
|
fn prepare_overwrite(&self, page_idx: usize) -> Result<Frame> {
|
||||||
/// and we do not care about the content on the page.
|
if let Some(pager) = &self.pager {
|
||||||
fn prepare_overwrite(&self, page_idx: usize, is_cow_vmo: bool) -> Result<Frame> {
|
pager.commit_overwrite(page_idx)
|
||||||
let page = if let Some(pager) = &self.pager
|
|
||||||
&& !is_cow_vmo
|
|
||||||
{
|
|
||||||
pager.commit_overwrite(page_idx)?
|
|
||||||
} else {
|
} else {
|
||||||
FrameAllocOptions::new(1).alloc_single()?
|
Ok(FrameAllocOptions::new(1).alloc_single()?)
|
||||||
};
|
}
|
||||||
Ok(page)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_with_cursor(
|
fn commit_with_cursor(
|
||||||
&self,
|
&self,
|
||||||
cursor: &mut CursorMut<'_, Frame, VmoMark>,
|
cursor: &mut CursorMut<'_, Frame>,
|
||||||
is_cow_vmo: bool,
|
|
||||||
commit_flags: CommitFlags,
|
commit_flags: CommitFlags,
|
||||||
) -> Result<Frame> {
|
) -> Result<Frame> {
|
||||||
let (new_page, is_exclusive) = {
|
let new_page = {
|
||||||
let is_exclusive = cursor.is_marked(VmoMark::ExclusivePage);
|
|
||||||
if let Some(committed_page) = cursor.load() {
|
if let Some(committed_page) = cursor.load() {
|
||||||
// The necessary and sufficient condition for triggering the COW mechanism is that
|
|
||||||
// the current VMO requires copy-on-write, there is an impending write operation to the page,
|
|
||||||
// and the page is not exclusive.
|
|
||||||
let trigger_cow = is_cow_vmo && commit_flags.will_write() && !is_exclusive;
|
|
||||||
if !trigger_cow {
|
|
||||||
// Fast path: return the page directly.
|
// Fast path: return the page directly.
|
||||||
return Ok(committed_page.clone());
|
return Ok(committed_page.clone());
|
||||||
}
|
|
||||||
|
|
||||||
if commit_flags.will_overwrite() {
|
|
||||||
(FrameAllocOptions::new(1).alloc_single()?, true)
|
|
||||||
} else {
|
|
||||||
(clone_page(&committed_page)?, true)
|
|
||||||
}
|
|
||||||
} else if commit_flags.will_overwrite() {
|
} else if commit_flags.will_overwrite() {
|
||||||
// In this case, the page will be completely overwritten. The page only needs to
|
// In this case, the page will be completely overwritten.
|
||||||
// be marked as `ExclusivePage` when the current VMO is a cow VMO.
|
self.prepare_overwrite(cursor.index() as usize)?
|
||||||
(
|
|
||||||
self.prepare_overwrite(cursor.index() as usize, is_cow_vmo)?,
|
|
||||||
is_cow_vmo,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
self.prepare_page(cursor.index() as usize, is_cow_vmo, commit_flags)?
|
self.prepare_page(cursor.index() as usize)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cursor.store(new_page.clone());
|
cursor.store(new_page.clone());
|
||||||
if is_exclusive {
|
|
||||||
cursor.set_mark(VmoMark::ExclusivePage).unwrap();
|
|
||||||
}
|
|
||||||
Ok(new_page)
|
Ok(new_page)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the page corresponding to the target offset in the VMO and return that page.
|
/// Commits the page corresponding to the target offset in the VMO and return that page.
|
||||||
/// If the current offset has already been committed, the page will be returned directly.
|
/// If the current offset has already been committed, the page will be returned directly.
|
||||||
/// During the commit process, the Copy-On-Write (COW) mechanism may be triggered depending on the circumstances.
|
pub fn commit_page(&self, offset: usize) -> Result<Frame> {
|
||||||
pub fn commit_page(&self, offset: usize, will_write: bool) -> Result<Frame> {
|
let page_idx = offset / PAGE_SIZE;
|
||||||
let page_idx = offset / PAGE_SIZE + self.page_idx_offset;
|
|
||||||
self.pages.with(|pages, size| {
|
self.pages.with(|pages, size| {
|
||||||
let is_cow_vmo = pages.is_marked(VmoMark::CowVmo);
|
if offset >= size {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "the offset is outside the VMO");
|
||||||
|
}
|
||||||
let mut cursor = pages.cursor_mut(page_idx as u64);
|
let mut cursor = pages.cursor_mut(page_idx as u64);
|
||||||
let commit_flags = if will_write {
|
self.commit_with_cursor(&mut cursor, CommitFlags::empty())
|
||||||
CommitFlags::WILL_WRITE
|
|
||||||
} else {
|
|
||||||
CommitFlags::empty()
|
|
||||||
};
|
|
||||||
self.commit_with_cursor(&mut cursor, is_cow_vmo, commit_flags)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decommit the page corresponding to the target offset in the VMO.
|
/// Decommits the page corresponding to the target offset in the VMO.
|
||||||
fn decommit_page(&mut self, offset: usize) -> Result<()> {
|
fn decommit_page(&mut self, offset: usize) -> Result<()> {
|
||||||
let page_idx = offset / PAGE_SIZE + self.page_idx_offset;
|
let page_idx = offset / PAGE_SIZE;
|
||||||
self.pages.with(|pages, size| {
|
self.pages.with(|pages, size| {
|
||||||
let is_cow_vmo = pages.is_marked(VmoMark::CowVmo);
|
if offset >= size {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "the offset is outside the VMO");
|
||||||
|
}
|
||||||
let mut cursor = pages.cursor_mut(page_idx as u64);
|
let mut cursor = pages.cursor_mut(page_idx as u64);
|
||||||
if cursor.remove().is_some()
|
if cursor.remove().is_some()
|
||||||
&& let Some(pager) = &self.pager
|
&& let Some(pager) = &self.pager
|
||||||
&& !is_cow_vmo
|
|
||||||
{
|
{
|
||||||
pager.decommit_page(page_idx)?;
|
pager.decommit_page(page_idx)?;
|
||||||
}
|
}
|
||||||
@ -355,7 +260,7 @@ impl Vmo_ {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit a range of pages in the VMO, and perform the operation
|
/// Commits a range of pages in the VMO, and perform the operation
|
||||||
/// on each page in the range in turn.
|
/// on each page in the range in turn.
|
||||||
pub fn commit_and_operate<F>(
|
pub fn commit_and_operate<F>(
|
||||||
&self,
|
&self,
|
||||||
@ -371,15 +276,10 @@ impl Vmo_ {
|
|||||||
return_errno_with_message!(Errno::EINVAL, "operated range exceeds the vmo size");
|
return_errno_with_message!(Errno::EINVAL, "operated range exceeds the vmo size");
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw_page_idx_range = get_page_idx_range(range);
|
let page_idx_range = get_page_idx_range(range);
|
||||||
let page_idx_range = (raw_page_idx_range.start + self.page_idx_offset)
|
|
||||||
..(raw_page_idx_range.end + self.page_idx_offset);
|
|
||||||
|
|
||||||
let is_cow_vmo = pages.is_marked(VmoMark::CowVmo);
|
|
||||||
let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
|
let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
|
||||||
for page_idx in page_idx_range {
|
for page_idx in page_idx_range {
|
||||||
let committed_page =
|
let committed_page = self.commit_with_cursor(&mut cursor, commit_flags)?;
|
||||||
self.commit_with_cursor(&mut cursor, is_cow_vmo, commit_flags)?;
|
|
||||||
operate(committed_page);
|
operate(committed_page);
|
||||||
cursor.next();
|
cursor.next();
|
||||||
}
|
}
|
||||||
@ -387,15 +287,19 @@ impl Vmo_ {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decommit a range of pages in the VMO.
|
/// Decommits a range of pages in the VMO.
|
||||||
pub fn decommit(&self, range: Range<usize>) -> Result<()> {
|
pub fn decommit(&self, range: Range<usize>) -> Result<()> {
|
||||||
self.pages.with(|pages, size| {
|
self.pages.with(|pages, size| {
|
||||||
|
if range.end > size {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "operated range exceeds the vmo size");
|
||||||
|
}
|
||||||
|
|
||||||
self.decommit_pages(pages, range)?;
|
self.decommit_pages(pages, range)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the specified amount of buffer content starting from the target offset in the VMO.
|
/// Reads the specified amount of buffer content starting from the target offset in the VMO.
|
||||||
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
let read_len = buf.len();
|
let read_len = buf.len();
|
||||||
let read_range = offset..(offset + read_len);
|
let read_range = offset..(offset + read_len);
|
||||||
@ -410,7 +314,7 @@ impl Vmo_ {
|
|||||||
self.commit_and_operate(&read_range, read, CommitFlags::empty())
|
self.commit_and_operate(&read_range, read, CommitFlags::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the specified amount of buffer content starting from the target offset in the VMO.
|
/// Writes the specified amount of buffer content starting from the target offset in the VMO.
|
||||||
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||||
let write_len = buf.len();
|
let write_len = buf.len();
|
||||||
let write_range = offset..(offset + write_len);
|
let write_range = offset..(offset + write_len);
|
||||||
@ -423,14 +327,14 @@ impl Vmo_ {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if write_range.len() < PAGE_SIZE {
|
if write_range.len() < PAGE_SIZE {
|
||||||
self.commit_and_operate(&write_range, write, CommitFlags::WILL_WRITE)?;
|
self.commit_and_operate(&write_range, write, CommitFlags::empty())?;
|
||||||
} else {
|
} else {
|
||||||
let temp = write_range.start + PAGE_SIZE - 1;
|
let temp = write_range.start + PAGE_SIZE - 1;
|
||||||
let up_align_start = temp - temp % PAGE_SIZE;
|
let up_align_start = temp - temp % PAGE_SIZE;
|
||||||
let down_align_end = write_range.end - write_range.end % PAGE_SIZE;
|
let down_align_end = write_range.end - write_range.end % PAGE_SIZE;
|
||||||
if write_range.start != up_align_start {
|
if write_range.start != up_align_start {
|
||||||
let head_range = write_range.start..up_align_start;
|
let head_range = write_range.start..up_align_start;
|
||||||
self.commit_and_operate(&head_range, &mut write, CommitFlags::WILL_WRITE)?;
|
self.commit_and_operate(&head_range, &mut write, CommitFlags::empty())?;
|
||||||
}
|
}
|
||||||
if up_align_start != down_align_end {
|
if up_align_start != down_align_end {
|
||||||
let mid_range = up_align_start..down_align_end;
|
let mid_range = up_align_start..down_align_end;
|
||||||
@ -438,17 +342,12 @@ impl Vmo_ {
|
|||||||
}
|
}
|
||||||
if down_align_end != write_range.end {
|
if down_align_end != write_range.end {
|
||||||
let tail_range = down_align_end..write_range.end;
|
let tail_range = down_align_end..write_range.end;
|
||||||
self.commit_and_operate(&tail_range, &mut write, CommitFlags::WILL_WRITE)?;
|
self.commit_and_operate(&tail_range, &mut write, CommitFlags::empty())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_cow_vmo = self.is_cow_vmo();
|
if let Some(pager) = &self.pager {
|
||||||
if let Some(pager) = &self.pager
|
let page_idx_range = get_page_idx_range(&write_range);
|
||||||
&& !is_cow_vmo
|
|
||||||
{
|
|
||||||
let raw_page_idx_range = get_page_idx_range(&write_range);
|
|
||||||
let page_idx_range = (raw_page_idx_range.start + self.page_idx_offset)
|
|
||||||
..(raw_page_idx_range.end + self.page_idx_offset);
|
|
||||||
for page_idx in page_idx_range {
|
for page_idx in page_idx_range {
|
||||||
pager.update_page(page_idx)?;
|
pager.update_page(page_idx)?;
|
||||||
}
|
}
|
||||||
@ -456,118 +355,19 @@ impl Vmo_ {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the target range in current VMO.
|
/// Clears the target range in current VMO.
|
||||||
pub fn clear(&self, range: Range<usize>) -> Result<()> {
|
pub fn clear(&self, range: Range<usize>) -> Result<()> {
|
||||||
let buffer = vec![0u8; range.end - range.start];
|
let buffer = vec![0u8; range.end - range.start];
|
||||||
self.write_bytes(range.start, &buffer)?;
|
self.write_bytes(range.start, &buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the size of current VMO.
|
/// Returns the size of current VMO.
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.pages.with(|pages, size| size)
|
self.pages.with(|_, size| size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the page index offset of current VMO in corresponding pages.
|
/// Resizes current VMO to target size.
|
||||||
pub fn page_idx_offset(&self) -> usize {
|
|
||||||
self.page_idx_offset
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clone the current `pages` to the child VMO.
|
|
||||||
///
|
|
||||||
/// Depending on the type of the VMO and the child, there are 4 conditions:
|
|
||||||
/// 1. For a slice child, directly share the current `pages` with that child.
|
|
||||||
/// 2. For a COW child, and the current VMO requires COW, it is necessary to clear the
|
|
||||||
/// ExclusivePage mark in the current `pages` and clone a new `pages` to the child.
|
|
||||||
/// 3. For a COW child, where the current VMO does not require COW and is a File-backed VMO.
|
|
||||||
/// In this case, a new `pages` needs to be cloned to the child, and the child's `pages`
|
|
||||||
/// require COW. The current `pages` do not need COW as they need to remain consistent with the pager.
|
|
||||||
/// 4. For a COW child, where the current VMO does not require COW and is an Anonymous VMO.
|
|
||||||
/// In this case, a new `pages` needs to be cloned to the child, and both the current `pages` and
|
|
||||||
/// the child's `pages` require COW.
|
|
||||||
pub fn clone_pages_for_child(
|
|
||||||
&self,
|
|
||||||
child_type: ChildType,
|
|
||||||
child_flags: VmoFlags,
|
|
||||||
range: &Range<usize>,
|
|
||||||
) -> Result<Pages> {
|
|
||||||
let child_vmo_start = range.start;
|
|
||||||
let child_vmo_end = range.end;
|
|
||||||
debug_assert!(child_vmo_start % PAGE_SIZE == 0);
|
|
||||||
debug_assert!(child_vmo_end % PAGE_SIZE == 0);
|
|
||||||
if child_vmo_start % PAGE_SIZE != 0 || child_vmo_end % PAGE_SIZE != 0 {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "VMO range does not aligned with PAGE_SIZE");
|
|
||||||
}
|
|
||||||
|
|
||||||
match child_type {
|
|
||||||
ChildType::Slice => {
|
|
||||||
if child_flags.contains(VmoFlags::RESIZABLE) {
|
|
||||||
return_errno_with_message!(
|
|
||||||
Errno::EINVAL,
|
|
||||||
"a slice child VMO cannot be resizable"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Pages::Nonresizable(ref pages, size) = self.pages else {
|
|
||||||
return_errno_with_message!(
|
|
||||||
Errno::EINVAL,
|
|
||||||
"a resizable VMO cannot have a slice child"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// A slice child should be inside parent VMO's range
|
|
||||||
debug_assert!(child_vmo_end <= size);
|
|
||||||
if child_vmo_end > size {
|
|
||||||
return_errno_with_message!(
|
|
||||||
Errno::EINVAL,
|
|
||||||
"a slice child VMO cannot exceed its parent VMO's size"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Condition 1.
|
|
||||||
Ok(Pages::Nonresizable(pages.clone(), range.len()))
|
|
||||||
}
|
|
||||||
ChildType::Cow => {
|
|
||||||
let new_pages = self.pages.with(|pages, size| {
|
|
||||||
// A Copy-on-Write child should intersect with parent VMO
|
|
||||||
debug_assert!(child_vmo_start <= size);
|
|
||||||
if child_vmo_start > size {
|
|
||||||
return_errno_with_message!(
|
|
||||||
Errno::EINVAL,
|
|
||||||
"a COW VMO should overlap with its parent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let self_is_cow = pages.is_marked(VmoMark::CowVmo);
|
|
||||||
if self_is_cow {
|
|
||||||
// Condition 2.
|
|
||||||
pages.unset_mark_all(VmoMark::ExclusivePage);
|
|
||||||
return Ok(pages.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.pager.is_some() {
|
|
||||||
// Condition 3.
|
|
||||||
let mut cloned_pages = pages.clone();
|
|
||||||
cloned_pages.set_mark(VmoMark::CowVmo);
|
|
||||||
return Ok(cloned_pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Condition 4.
|
|
||||||
pages.set_mark(VmoMark::CowVmo);
|
|
||||||
Ok(pages.clone())
|
|
||||||
})?;
|
|
||||||
if child_flags.contains(VmoFlags::RESIZABLE) {
|
|
||||||
Ok(Pages::Resizable(Mutex::new((new_pages, range.len()))))
|
|
||||||
} else {
|
|
||||||
Ok(Pages::Nonresizable(
|
|
||||||
Arc::new(Mutex::new(new_pages)),
|
|
||||||
range.len(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resize current VMO to target size.
|
|
||||||
pub fn resize(&self, new_size: usize) -> Result<()> {
|
pub fn resize(&self, new_size: usize) -> Result<()> {
|
||||||
assert!(self.flags.contains(VmoFlags::RESIZABLE));
|
assert!(self.flags.contains(VmoFlags::RESIZABLE));
|
||||||
let new_size = new_size.align_up(PAGE_SIZE);
|
let new_size = new_size.align_up(PAGE_SIZE);
|
||||||
@ -588,20 +388,12 @@ impl Vmo_ {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decommit_pages(
|
fn decommit_pages(&self, pages: &mut XArray<Frame>, range: Range<usize>) -> Result<()> {
|
||||||
&self,
|
let page_idx_range = get_page_idx_range(&range);
|
||||||
pages: &mut XArray<Frame, VmoMark>,
|
|
||||||
range: Range<usize>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let raw_page_idx_range = get_page_idx_range(&range);
|
|
||||||
let page_idx_range = (raw_page_idx_range.start + self.page_idx_offset)
|
|
||||||
..(raw_page_idx_range.end + self.page_idx_offset);
|
|
||||||
let is_cow_vmo = pages.is_marked(VmoMark::CowVmo);
|
|
||||||
let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
|
let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
|
||||||
for page_idx in page_idx_range {
|
for page_idx in page_idx_range {
|
||||||
if cursor.remove().is_some()
|
if cursor.remove().is_some()
|
||||||
&& let Some(pager) = &self.pager
|
&& let Some(pager) = &self.pager
|
||||||
&& !is_cow_vmo
|
|
||||||
{
|
{
|
||||||
pager.decommit_page(page_idx)?;
|
pager.decommit_page(page_idx)?;
|
||||||
}
|
}
|
||||||
@ -610,24 +402,25 @@ impl Vmo_ {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether a page is committed.
|
/// Determines whether a page is committed.
|
||||||
pub fn is_page_committed(&self, page_idx: usize) -> bool {
|
pub fn is_page_committed(&self, page_idx: usize) -> bool {
|
||||||
self.pages.with(|pages, size| {
|
self.pages
|
||||||
pages
|
.with(|pages, _| pages.load(page_idx as u64).is_some())
|
||||||
.load((page_idx + self.page_idx_offset) as u64)
|
|
||||||
.is_some()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the flags of current VMO.
|
/// Returns the flags of current VMO.
|
||||||
pub fn flags(&self) -> VmoFlags {
|
pub fn flags(&self) -> VmoFlags {
|
||||||
self.flags
|
self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether the VMO is need COW mechanism.
|
fn replace(&self, page: Frame, page_idx: usize) -> Result<()> {
|
||||||
pub fn is_cow_vmo(&self) -> bool {
|
self.pages.with(|pages, size| {
|
||||||
self.pages
|
if page_idx >= size / PAGE_SIZE {
|
||||||
.with(|pages, size| pages.is_marked(VmoMark::CowVmo))
|
return_errno_with_message!(Errno::EINVAL, "the page index is outside of the vmo");
|
||||||
|
}
|
||||||
|
pages.store(page_idx as u64, page);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,22 +434,9 @@ impl<R> Vmo<R> {
|
|||||||
pub fn flags(&self) -> VmoFlags {
|
pub fn flags(&self) -> VmoFlags {
|
||||||
self.0.flags()
|
self.0.flags()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return whether a page is already committed
|
|
||||||
pub fn is_page_committed(&self, page_idx: usize) -> bool {
|
|
||||||
self.0.is_page_committed(page_idx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_committed_frame(&self, page_idx: usize, write_page: bool) -> Result<Frame> {
|
/// Gets the page index range that contains the offset range of VMO.
|
||||||
self.0.commit_page(page_idx * PAGE_SIZE, write_page)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_cow_vmo(&self) -> bool {
|
|
||||||
self.0.is_cow_vmo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get the page index range that contains the offset range of vmo
|
|
||||||
pub fn get_page_idx_range(vmo_offset_range: &Range<usize>) -> Range<usize> {
|
pub fn get_page_idx_range(vmo_offset_range: &Range<usize>) -> Range<usize> {
|
||||||
let start = vmo_offset_range.start.align_down(PAGE_SIZE);
|
let start = vmo_offset_range.start.align_down(PAGE_SIZE);
|
||||||
let end = vmo_offset_range.end.align_up(PAGE_SIZE);
|
let end = vmo_offset_range.end.align_up(PAGE_SIZE);
|
||||||
|
@ -4,18 +4,14 @@
|
|||||||
|
|
||||||
//! Options for allocating root and child VMOs.
|
//! Options for allocating root and child VMOs.
|
||||||
|
|
||||||
use core::{marker::PhantomData, ops::Range};
|
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_rights::{Dup, Rights, TRightSet, TRights, Write};
|
use aster_rights::{Rights, TRightSet, TRights};
|
||||||
use aster_rights_proc::require;
|
|
||||||
use ostd::{
|
use ostd::{
|
||||||
collections::xarray::XArray,
|
collections::xarray::XArray,
|
||||||
mm::{Frame, FrameAllocOptions},
|
mm::{Frame, FrameAllocOptions},
|
||||||
};
|
};
|
||||||
use typeflags_util::{SetExtend, SetExtendOp};
|
|
||||||
|
|
||||||
use super::{Pager, Pages, Vmo, VmoFlags, VmoMark, VmoRightsOp};
|
use super::{Pager, Pages, Vmo, VmoFlags};
|
||||||
use crate::{prelude::*, vm::vmo::Vmo_};
|
use crate::{prelude::*, vm::vmo::Vmo_};
|
||||||
|
|
||||||
/// Options for allocating a root VMO.
|
/// Options for allocating a root VMO.
|
||||||
@ -131,18 +127,17 @@ fn alloc_vmo_(size: usize, flags: VmoFlags, pager: Option<Arc<dyn Pager>>) -> Re
|
|||||||
if flags.contains(VmoFlags::RESIZABLE) {
|
if flags.contains(VmoFlags::RESIZABLE) {
|
||||||
Pages::Resizable(Mutex::new((pages, size)))
|
Pages::Resizable(Mutex::new((pages, size)))
|
||||||
} else {
|
} else {
|
||||||
Pages::Nonresizable(Arc::new(Mutex::new(pages)), size)
|
Pages::Nonresizable(Mutex::new(pages), size)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Vmo_ {
|
Ok(Vmo_ {
|
||||||
pager,
|
pager,
|
||||||
flags,
|
flags,
|
||||||
page_idx_offset: 0,
|
|
||||||
pages,
|
pages,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<Frame, VmoMark>> {
|
fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<Frame>> {
|
||||||
if flags.contains(VmoFlags::CONTIGUOUS) {
|
if flags.contains(VmoFlags::CONTIGUOUS) {
|
||||||
// if the vmo is continuous, we need to allocate frames for the vmo
|
// if the vmo is continuous, we need to allocate frames for the vmo
|
||||||
let frames_num = size / PAGE_SIZE;
|
let frames_num = size / PAGE_SIZE;
|
||||||
@ -163,317 +158,6 @@ fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for allocating a child VMO out of a parent VMO.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// A child VMO created from a parent VMO of _dynamic_ capability is also a
|
|
||||||
/// _dynamic_ capability.
|
|
||||||
/// ```
|
|
||||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions};
|
|
||||||
///
|
|
||||||
/// let parent_vmo = VmoOptions::new(PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// let child_vmo = parent_vmo.new_slice_child(0..PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert!(parent_vmo.rights() == child_vmo.rights());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// A child VMO created from a parent VMO of _static_ capability is also a
|
|
||||||
/// _static_ capability.
|
|
||||||
/// ```
|
|
||||||
/// use aster_nix::prelude::*;
|
|
||||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions};
|
|
||||||
///
|
|
||||||
/// let parent_vmo: Vmo<Full> = VmoOptions::new(PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// let child_vmo: Vmo<Full> = parent_vmo.new_slice_child(0..PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert!(parent_vmo.rights() == child_vmo.rights());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Normally, a child VMO is initially given the same set of access rights
|
|
||||||
/// as its parent (as shown above). But there is one exception:
|
|
||||||
/// if the child VMO is created as a COW child, then it is granted the Write
|
|
||||||
/// right regardless of whether the parent is writable or not.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions};
|
|
||||||
///
|
|
||||||
/// let parent_vmo = VmoOptions::new(PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap()
|
|
||||||
/// .restrict(Rights::DUP | Rights::READ);
|
|
||||||
/// let child_vmo = parent_vmo.new_cow_child(0..PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert!(child_vmo.rights().contains(Rights::WRITE));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above rule for COW VMO children also applies to static capabilities.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions};
|
|
||||||
///
|
|
||||||
/// let parent_vmo = VmoOptions::<TRights![Read, Dup]>::new(PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// let child_vmo = parent_vmo.new_cow_child(0..PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert!(child_vmo.rights().contains(Rights::WRITE));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// One can set VMO flags for a child VMO. Currently, the only flag that is
|
|
||||||
/// valid when creating VMO children is `VmoFlags::RESIZABLE`.
|
|
||||||
/// Note that a slice VMO child and its parent cannot not be resizable.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions};
|
|
||||||
///
|
|
||||||
/// let parent_vmo = VmoOptions::new(PAGE_SIZE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// let child_vmo = parent_vmo.new_cow_child(0..PAGE_SIZE)
|
|
||||||
/// // Make the child resizable!
|
|
||||||
/// .flags(VmoFlags::RESIZABLE)
|
|
||||||
/// .alloc()
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert!(parent_vmo.rights() == child_vmo.rights());
|
|
||||||
/// ```
|
|
||||||
pub struct VmoChildOptions<R, C> {
|
|
||||||
parent: Vmo<R>,
|
|
||||||
range: Range<usize>,
|
|
||||||
flags: VmoFlags,
|
|
||||||
// Specifies whether the child is a slice or a COW
|
|
||||||
marker: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TRights> VmoChildOptions<TRightSet<R>, VmoSliceChild> {
|
|
||||||
/// Creates a default set of options for creating a slice VMO child.
|
|
||||||
///
|
|
||||||
/// A slice child of a VMO, which has direct access to a range of memory
|
|
||||||
/// pages in the parent VMO. In other words, any updates of the parent will
|
|
||||||
/// reflect on the child, and vice versa.
|
|
||||||
///
|
|
||||||
/// The range of a child must be within that of the parent.
|
|
||||||
#[require(R > Dup)]
|
|
||||||
pub fn new_slice(parent: Vmo<TRightSet<R>>, range: Range<usize>) -> Self {
|
|
||||||
Self {
|
|
||||||
flags: parent.flags() & Self::PARENT_FLAGS_MASK,
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VmoChildOptions<Rights, VmoSliceChild> {
|
|
||||||
/// Creates a default set of options for creating a slice VMO child.
|
|
||||||
///
|
|
||||||
/// User should ensure parent have dup rights, otherwise this function will panic
|
|
||||||
///
|
|
||||||
/// A slice child of a VMO, which has direct access to a range of memory
|
|
||||||
/// pages in the parent VMO. In other words, any updates of the parent will
|
|
||||||
/// reflect on the child, and vice versa.
|
|
||||||
///
|
|
||||||
/// The range of a child must be within that of the parent.
|
|
||||||
pub fn new_slice_rights(parent: Vmo<Rights>, range: Range<usize>) -> Self {
|
|
||||||
parent
|
|
||||||
.check_rights(Rights::DUP)
|
|
||||||
.expect("function new_slice_rights should called with rights Dup");
|
|
||||||
Self {
|
|
||||||
flags: parent.flags(),
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> VmoChildOptions<R, VmoSliceChild> {
|
|
||||||
/// Flags that a VMO child inherits from its parent.
|
|
||||||
pub const PARENT_FLAGS_MASK: VmoFlags =
|
|
||||||
VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap();
|
|
||||||
/// Flags that a VMO child may differ from its parent.
|
|
||||||
pub const CHILD_FLAGS_MASK: VmoFlags = VmoFlags::empty();
|
|
||||||
|
|
||||||
/// Sets the VMO flags.
|
|
||||||
///
|
|
||||||
/// Only the flags among `Self::CHILD_FLAGS_MASK` may be set through this
|
|
||||||
/// method.
|
|
||||||
///
|
|
||||||
/// To set `VmoFlags::RESIZABLE`, the child must be COW.
|
|
||||||
///
|
|
||||||
/// The default value is `VmoFlags::empty()`.
|
|
||||||
pub fn flags(mut self, flags: VmoFlags) -> Self {
|
|
||||||
let inherited_flags = self.flags & Self::PARENT_FLAGS_MASK;
|
|
||||||
self.flags = inherited_flags | (flags & Self::CHILD_FLAGS_MASK);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> VmoChildOptions<R, VmoCowChild> {
|
|
||||||
/// Flags that a VMO child inherits from its parent.
|
|
||||||
pub const PARENT_FLAGS_MASK: VmoFlags =
|
|
||||||
VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap();
|
|
||||||
/// Flags that a VMO child may differ from its parent.
|
|
||||||
pub const CHILD_FLAGS_MASK: VmoFlags = VmoFlags::RESIZABLE;
|
|
||||||
/// Creates a default set of options for creating a copy-on-write (COW)
|
|
||||||
/// VMO child.
|
|
||||||
///
|
|
||||||
/// A COW VMO child behaves as if all its
|
|
||||||
/// memory pages are copied from the parent VMO upon creation, although
|
|
||||||
/// the copying is done lazily when the parent's memory pages are updated.
|
|
||||||
///
|
|
||||||
/// The range of a child may go beyond that of the parent.
|
|
||||||
/// Any pages that are beyond the parent's range are initially all zeros.
|
|
||||||
pub fn new_cow(parent: Vmo<R>, range: Range<usize>) -> Self {
|
|
||||||
Self {
|
|
||||||
flags: parent.flags(),
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the VMO flags.
|
|
||||||
///
|
|
||||||
/// Only the flags among `Self::CHILD_FLAGS_MASK` may be set through this
|
|
||||||
/// method.
|
|
||||||
///
|
|
||||||
/// To set `VmoFlags::RESIZABLE`, the child must be COW.
|
|
||||||
///
|
|
||||||
/// The default value is `VmoFlags::empty()`.
|
|
||||||
pub fn flags(mut self, flags: VmoFlags) -> Self {
|
|
||||||
let inherited_flags = self.flags & Self::PARENT_FLAGS_MASK;
|
|
||||||
self.flags = inherited_flags | (flags & Self::CHILD_FLAGS_MASK);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VmoChildOptions<Rights, VmoSliceChild> {
|
|
||||||
/// Allocates the child VMO.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// The child VMO is initially assigned all the parent's access rights.
|
|
||||||
pub fn alloc(self) -> Result<Vmo<Rights>> {
|
|
||||||
let VmoChildOptions {
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
flags,
|
|
||||||
..
|
|
||||||
} = self;
|
|
||||||
let Vmo(parent_vmo_, parent_rights) = parent;
|
|
||||||
let child_vmo_ = alloc_child_vmo_(parent_vmo_, range, flags, ChildType::Slice)?;
|
|
||||||
Ok(Vmo(Arc::new(child_vmo_), parent_rights))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VmoChildOptions<Rights, VmoCowChild> {
|
|
||||||
/// Allocates the child VMO.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// The child VMO is initially assigned all the parent's access rights.
|
|
||||||
pub fn alloc(self) -> Result<Vmo<Rights>> {
|
|
||||||
let VmoChildOptions {
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
flags,
|
|
||||||
..
|
|
||||||
} = self;
|
|
||||||
let Vmo(parent_vmo_, parent_rights) = parent;
|
|
||||||
let child_vmo_ = alloc_child_vmo_(parent_vmo_, range, flags, ChildType::Cow)?;
|
|
||||||
Ok(Vmo(Arc::new(child_vmo_), parent_rights))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TRights> VmoChildOptions<TRightSet<R>, VmoSliceChild> {
|
|
||||||
/// Allocates the child VMO.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// The child VMO is initially assigned all the parent's access rights.
|
|
||||||
pub fn alloc(self) -> Result<Vmo<TRightSet<R>>> {
|
|
||||||
let VmoChildOptions {
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
flags,
|
|
||||||
..
|
|
||||||
} = self;
|
|
||||||
let Vmo(parent_vmo_, parent_rights) = parent;
|
|
||||||
let child_vmo_ = alloc_child_vmo_(parent_vmo_, range, flags, ChildType::Slice)?;
|
|
||||||
Ok(Vmo(Arc::new(child_vmo_), parent_rights))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TRights> VmoChildOptions<TRightSet<R>, VmoCowChild> {
|
|
||||||
/// Allocates the child VMO.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// The child VMO is initially assigned all the parent's access rights
|
|
||||||
/// plus the Write right.
|
|
||||||
pub fn alloc(self) -> Result<Vmo<TRightSet<SetExtendOp<R, Write>>>>
|
|
||||||
where
|
|
||||||
R: SetExtend<Write>,
|
|
||||||
SetExtendOp<R, Write>: TRights,
|
|
||||||
{
|
|
||||||
let VmoChildOptions {
|
|
||||||
parent,
|
|
||||||
range,
|
|
||||||
flags,
|
|
||||||
..
|
|
||||||
} = self;
|
|
||||||
let Vmo(parent_vmo_, _) = parent;
|
|
||||||
let child_vmo_ = alloc_child_vmo_(parent_vmo_, range, flags, ChildType::Cow)?;
|
|
||||||
let right = SetExtendOp::<R, Write>::new();
|
|
||||||
Ok(Vmo(Arc::new(child_vmo_), TRightSet(right)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum ChildType {
|
|
||||||
Cow,
|
|
||||||
Slice,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_child_vmo_(
|
|
||||||
parent_vmo_: Arc<Vmo_>,
|
|
||||||
range: Range<usize>,
|
|
||||||
child_flags: VmoFlags,
|
|
||||||
child_type: ChildType,
|
|
||||||
) -> Result<Vmo_> {
|
|
||||||
let parent_page_idx_offset = range.start / PAGE_SIZE;
|
|
||||||
let child_pages = parent_vmo_.clone_pages_for_child(child_type, child_flags, &range)?;
|
|
||||||
let new_vmo = Vmo_ {
|
|
||||||
pager: parent_vmo_.pager.clone(),
|
|
||||||
flags: child_flags,
|
|
||||||
pages: child_pages,
|
|
||||||
page_idx_offset: parent_page_idx_offset + parent_vmo_.page_idx_offset(),
|
|
||||||
};
|
|
||||||
Ok(new_vmo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type to specify the "type" of a child, which is either a slice or a COW.
|
|
||||||
pub trait VmoChildType {}
|
|
||||||
|
|
||||||
/// A type to mark a child is slice.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct VmoSliceChild;
|
|
||||||
impl VmoChildType for VmoSliceChild {}
|
|
||||||
|
|
||||||
/// A type to mark a child is COW.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct VmoCowChild;
|
|
||||||
impl VmoChildType for VmoCowChild {}
|
|
||||||
|
|
||||||
#[cfg(ktest)]
|
#[cfg(ktest)]
|
||||||
mod test {
|
mod test {
|
||||||
use aster_rights::Full;
|
use aster_rights::Full;
|
||||||
@ -512,53 +196,6 @@ mod test {
|
|||||||
assert_eq!(read_val, 0x78563412)
|
assert_eq!(read_val, 0x78563412)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ktest]
|
|
||||||
fn slice_child() {
|
|
||||||
let parent = VmoOptions::<Full>::new(2 * PAGE_SIZE).alloc().unwrap();
|
|
||||||
let parent_dup = parent.dup();
|
|
||||||
let slice_child = VmoChildOptions::new_slice(parent_dup, 0..PAGE_SIZE)
|
|
||||||
.alloc()
|
|
||||||
.unwrap();
|
|
||||||
// write parent, read child
|
|
||||||
parent.write_val(1, &42u8).unwrap();
|
|
||||||
assert_eq!(slice_child.read_val::<u8>(1).unwrap(), 42);
|
|
||||||
// write child, read parent
|
|
||||||
slice_child.write_val(99, &0x1234u32).unwrap();
|
|
||||||
assert_eq!(parent.read_val::<u32>(99).unwrap(), 0x1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ktest]
|
|
||||||
fn cow_child() {
|
|
||||||
let parent = VmoOptions::<Full>::new(2 * PAGE_SIZE).alloc().unwrap();
|
|
||||||
parent.write_val(1, &42u8).unwrap();
|
|
||||||
parent.write_val(2, &16u8).unwrap();
|
|
||||||
let parent_dup = parent.dup();
|
|
||||||
let cow_child = VmoChildOptions::new_cow(parent_dup, 0..10 * PAGE_SIZE)
|
|
||||||
.alloc()
|
|
||||||
.unwrap();
|
|
||||||
// Read child.
|
|
||||||
assert_eq!(cow_child.read_val::<u8>(1).unwrap(), 42);
|
|
||||||
assert_eq!(cow_child.read_val::<u8>(2).unwrap(), 16);
|
|
||||||
// Write parent to trigger copy-on-write. read child and parent.
|
|
||||||
parent.write_val(1, &64u8).unwrap();
|
|
||||||
assert_eq!(parent.read_val::<u8>(1).unwrap(), 64);
|
|
||||||
assert_eq!(cow_child.read_val::<u8>(1).unwrap(), 42);
|
|
||||||
// Write child to trigger copy on write, read child and parent
|
|
||||||
cow_child.write_val(2, &0x1234u32).unwrap();
|
|
||||||
assert_eq!(cow_child.read_val::<u32>(2).unwrap(), 0x1234);
|
|
||||||
assert_eq!(cow_child.read_val::<u8>(1).unwrap(), 42);
|
|
||||||
assert_eq!(parent.read_val::<u8>(2).unwrap(), 16);
|
|
||||||
assert_eq!(parent.read_val::<u8>(1).unwrap(), 64);
|
|
||||||
// Write parent on already-copied page
|
|
||||||
parent.write_val(1, &123u8).unwrap();
|
|
||||||
assert_eq!(parent.read_val::<u8>(1).unwrap(), 123);
|
|
||||||
assert_eq!(cow_child.read_val::<u8>(1).unwrap(), 42);
|
|
||||||
// Write parent on not-copied page
|
|
||||||
parent.write_val(2, &12345u32).unwrap();
|
|
||||||
assert_eq!(parent.read_val::<u32>(2).unwrap(), 12345);
|
|
||||||
assert_eq!(cow_child.read_val::<u32>(2).unwrap(), 0x1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ktest]
|
#[ktest]
|
||||||
fn resize() {
|
fn resize() {
|
||||||
let vmo = VmoOptions::<Full>::new(PAGE_SIZE)
|
let vmo = VmoOptions::<Full>::new(PAGE_SIZE)
|
||||||
@ -573,17 +210,4 @@ mod test {
|
|||||||
vmo.resize(PAGE_SIZE).unwrap();
|
vmo.resize(PAGE_SIZE).unwrap();
|
||||||
assert_eq!(vmo.read_val::<u8>(10).unwrap(), 42);
|
assert_eq!(vmo.read_val::<u8>(10).unwrap(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ktest]
|
|
||||||
fn resize_cow() {
|
|
||||||
let vmo = VmoOptions::<Full>::new(10 * PAGE_SIZE)
|
|
||||||
.flags(VmoFlags::RESIZABLE)
|
|
||||||
.alloc()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cow_child = VmoChildOptions::new_cow(vmo, 0..PAGE_SIZE).alloc().unwrap();
|
|
||||||
|
|
||||||
cow_child.resize(2 * PAGE_SIZE).unwrap();
|
|
||||||
assert_eq!(cow_child.size(), 2 * PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,74 +6,17 @@ use aster_rights::{Dup, Rights, TRightSet, TRights, Write};
|
|||||||
use aster_rights_proc::require;
|
use aster_rights_proc::require;
|
||||||
use ostd::mm::{Frame, VmIo};
|
use ostd::mm::{Frame, VmIo};
|
||||||
|
|
||||||
use super::{
|
use super::{CommitFlags, Vmo, VmoRightsOp};
|
||||||
options::{VmoCowChild, VmoSliceChild},
|
|
||||||
CommitFlags, Vmo, VmoChildOptions, VmoRightsOp,
|
|
||||||
};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl<R: TRights> Vmo<TRightSet<R>> {
|
impl<R: TRights> Vmo<TRightSet<R>> {
|
||||||
/// Creates a new slice VMO through a set of VMO child options.
|
/// Commits a page at specific offset.
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
|
||||||
/// let child_size = parent.size();
|
|
||||||
/// let child = parent.new_slice_child(0..child_size).alloc().unwrap();
|
|
||||||
/// assert!(child.size() == child_size);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For more details on the available options, see `VmoChildOptions`.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// This method requires the Dup right.
|
|
||||||
///
|
|
||||||
/// The new VMO child will be of the same capability flavor as the parent;
|
|
||||||
/// so are the access rights.
|
|
||||||
#[require(R > Dup)]
|
|
||||||
pub fn new_slice_child(
|
|
||||||
&self,
|
|
||||||
range: Range<usize>,
|
|
||||||
) -> VmoChildOptions<TRightSet<R>, VmoSliceChild> {
|
|
||||||
let dup_self = self.dup();
|
|
||||||
VmoChildOptions::new_slice(dup_self, range)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new COW VMO through a set of VMO child options.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
|
||||||
/// let child_size = 2 * parent.size();
|
|
||||||
/// let child = parent.new_cow_child(0..child_size).alloc().unwrap();
|
|
||||||
/// assert!(child.size() == child_size);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For more details on the available options, see `VmoChildOptions`.
|
|
||||||
///
|
|
||||||
/// # Access rights
|
|
||||||
///
|
|
||||||
/// This method requires the Dup right.
|
|
||||||
///
|
|
||||||
/// The new VMO child will be of the same capability flavor as the parent.
|
|
||||||
/// The child will be given the access rights of the parent
|
|
||||||
/// plus the Write right.
|
|
||||||
#[require(R > Dup)]
|
|
||||||
pub fn new_cow_child(&self, range: Range<usize>) -> VmoChildOptions<TRightSet<R>, VmoCowChild> {
|
|
||||||
let dup_self = self.dup();
|
|
||||||
VmoChildOptions::new_cow(dup_self, range)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// commit a page at specific offset
|
|
||||||
pub fn commit_page(&self, offset: usize) -> Result<Frame> {
|
pub fn commit_page(&self, offset: usize) -> Result<Frame> {
|
||||||
self.check_rights(Rights::WRITE)?;
|
self.check_rights(Rights::WRITE)?;
|
||||||
self.0.commit_page(offset, false)
|
self.0.commit_page(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the pages specified in the range (in bytes).
|
/// Commits the pages specified in the range (in bytes).
|
||||||
///
|
///
|
||||||
/// The range must be within the size of the VMO.
|
/// The range must be within the size of the VMO.
|
||||||
///
|
///
|
||||||
@ -89,7 +32,7 @@ impl<R: TRights> Vmo<TRightSet<R>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decommit the pages specified in the range (in bytes).
|
/// Decommits the pages specified in the range (in bytes).
|
||||||
///
|
///
|
||||||
/// The range must be within the size of the VMO.
|
/// The range must be within the size of the VMO.
|
||||||
///
|
///
|
||||||
@ -137,6 +80,29 @@ impl<R: TRights> Vmo<TRightSet<R>> {
|
|||||||
Vmo(self.0.clone(), self.1)
|
Vmo(self.0.clone(), self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new VMO that replicates the original capability, initially representing
|
||||||
|
/// the same physical pages.
|
||||||
|
/// Changes to the permissions and commits/replacements of internal pages in the original VMO
|
||||||
|
/// and the new VMO will not affect each other.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Dup right.
|
||||||
|
#[require(R > Dup | Write)]
|
||||||
|
pub fn dup_independent(&self) -> Self {
|
||||||
|
Vmo(Arc::new(super::Vmo_::clone(&self.0)), self.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the page at the `page_idx` in the VMO with the input `page`.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Write right.
|
||||||
|
#[require(R > Write)]
|
||||||
|
pub fn replace(&self, page: Frame, page_idx: usize) -> Result<()> {
|
||||||
|
self.0.replace(page, page_idx)
|
||||||
|
}
|
||||||
|
|
||||||
/// Strict the access rights.
|
/// Strict the access rights.
|
||||||
#[require(R > R1)]
|
#[require(R > R1)]
|
||||||
pub fn restrict<R1: TRights>(self) -> Vmo<TRightSet<R1>> {
|
pub fn restrict<R1: TRights>(self) -> Vmo<TRightSet<R1>> {
|
||||||
|
@ -43,7 +43,7 @@ static_assertions = "1.1.0"
|
|||||||
trapframe = "0.10.0"
|
trapframe = "0.10.0"
|
||||||
unwinding = { version = "0.2.2", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] }
|
unwinding = { version = "0.2.2", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] }
|
||||||
volatile = { version = "0.4.5", features = ["unstable"] }
|
volatile = { version = "0.4.5", features = ["unstable"] }
|
||||||
xarray = { git = "https://github.com/asterinas/xarray", rev = "72a4067", version = "0.1.0" }
|
xarray = { git = "https://github.com/asterinas/xarray", version = "0.1.0" }
|
||||||
|
|
||||||
[target.x86_64-unknown-none.dependencies]
|
[target.x86_64-unknown-none.dependencies]
|
||||||
x86_64 = "0.14.2"
|
x86_64 = "0.14.2"
|
||||||
|
Reference in New Issue
Block a user