Remove `Rights` from VMO
This commit is contained in:
parent
77ef9e0368
commit
89e759894f
|
|
@ -6,7 +6,6 @@
|
|||
use core::ops::Range;
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Full;
|
||||
use bitvec::prelude::*;
|
||||
|
||||
use super::{
|
||||
|
|
@ -37,7 +36,7 @@ pub(super) struct ExfatBitmap {
|
|||
impl ExfatBitmap {
|
||||
pub(super) fn load(
|
||||
fs_weak: Weak<ExfatFs>,
|
||||
root_page_cache: Vmo<Full>,
|
||||
root_page_cache: &Vmo,
|
||||
root_chain: ExfatChain,
|
||||
) -> Result<Self> {
|
||||
let dentry_iterator = ExfatDentryIterator::new(root_page_cache, 0, None)?;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use core::{fmt::Display, ops::Range};
|
||||
|
||||
use aster_rights::Full;
|
||||
use ostd::mm::VmIo;
|
||||
|
||||
use super::{
|
||||
|
|
@ -278,7 +277,7 @@ impl ExfatDentrySet {
|
|||
Self::new(dentries, false)
|
||||
}
|
||||
|
||||
pub(super) fn read_from(page_cache: Vmo<Full>, offset: usize) -> Result<Self> {
|
||||
pub(super) fn read_from(page_cache: &Vmo, offset: usize) -> Result<Self> {
|
||||
let mut iter = ExfatDentryIterator::new(page_cache, offset, None)?;
|
||||
let primary_dentry_result = iter.next();
|
||||
|
||||
|
|
@ -439,17 +438,17 @@ impl Checksum for ExfatDentrySet {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct ExfatDentryIterator {
|
||||
pub(super) struct ExfatDentryIterator<'a> {
|
||||
/// The dentry position in current inode.
|
||||
entry: u32,
|
||||
/// The page cache of the iterated inode.
|
||||
page_cache: Vmo<Full>,
|
||||
page_cache: &'a Vmo,
|
||||
/// Remaining size that can be iterated. If none, iterate through the whole cluster chain.
|
||||
size: Option<usize>,
|
||||
}
|
||||
|
||||
impl ExfatDentryIterator {
|
||||
pub fn new(page_cache: Vmo<Full>, offset: usize, size: Option<usize>) -> Result<Self> {
|
||||
impl<'a> ExfatDentryIterator<'a> {
|
||||
pub fn new(page_cache: &'a Vmo, offset: usize, size: Option<usize>) -> Result<Self> {
|
||||
if size.is_some() && size.unwrap() % DENTRY_SIZE != 0 {
|
||||
return_errno_with_message!(Errno::EINVAL, "remaining size unaligned to dentry size")
|
||||
}
|
||||
|
|
@ -466,7 +465,7 @@ impl ExfatDentryIterator {
|
|||
}
|
||||
}
|
||||
|
||||
impl Iterator for ExfatDentryIterator {
|
||||
impl Iterator for ExfatDentryIterator<'_> {
|
||||
type Item = Result<ExfatDentry>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
|
|
|||
|
|
@ -98,17 +98,12 @@ impl ExfatFs {
|
|||
|
||||
let root = ExfatInode::build_root_inode(weak_fs.clone(), root_chain.clone())?;
|
||||
|
||||
let upcase_table = ExfatUpcaseTable::load(
|
||||
weak_fs.clone(),
|
||||
root.page_cache().unwrap(),
|
||||
root_chain.clone(),
|
||||
)?;
|
||||
let root_page_cache = root.page_cache().unwrap();
|
||||
|
||||
let bitmap = ExfatBitmap::load(
|
||||
weak_fs.clone(),
|
||||
root.page_cache().unwrap(),
|
||||
root_chain.clone(),
|
||||
)?;
|
||||
let upcase_table =
|
||||
ExfatUpcaseTable::load(weak_fs.clone(), &root_page_cache, root_chain.clone())?;
|
||||
|
||||
let bitmap = ExfatBitmap::load(weak_fs.clone(), &root_page_cache, root_chain.clone())?;
|
||||
|
||||
*exfat_fs.bitmap.lock() = bitmap;
|
||||
*exfat_fs.upcase_table.lock() = upcase_table;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use aster_block::{
|
|||
id::{Bid, BlockId},
|
||||
BLOCK_SIZE,
|
||||
};
|
||||
use aster_rights::Full;
|
||||
use ostd::mm::{io_util::HasVmReaderWriter, Segment, VmIo};
|
||||
|
||||
use super::{
|
||||
|
|
@ -247,7 +246,7 @@ impl ExfatInodeInner {
|
|||
return Ok((0, 0));
|
||||
}
|
||||
|
||||
let iterator = ExfatDentryIterator::new(self.page_cache.pages().dup(), 0, Some(self.size))?;
|
||||
let iterator = ExfatDentryIterator::new(self.page_cache.pages(), 0, Some(self.size))?;
|
||||
let mut sub_inodes = 0;
|
||||
let mut sub_dirs = 0;
|
||||
for dentry_result in iterator {
|
||||
|
|
@ -314,7 +313,7 @@ impl ExfatInodeInner {
|
|||
// Need to read the latest dentry set from parent inode.
|
||||
|
||||
let mut dentry_set =
|
||||
ExfatDentrySet::read_from(page_cache.dup(), self.dentry_entry as usize * DENTRY_SIZE)?;
|
||||
ExfatDentrySet::read_from(&page_cache, self.dentry_entry as usize * DENTRY_SIZE)?;
|
||||
|
||||
let mut file_dentry = dentry_set.get_file_dentry();
|
||||
let mut stream_dentry = dentry_set.get_stream_dentry();
|
||||
|
|
@ -376,7 +375,7 @@ impl ExfatInodeInner {
|
|||
let fs = self.fs();
|
||||
let cluster_size = fs.cluster_size();
|
||||
|
||||
let mut iter = ExfatDentryIterator::new(self.page_cache.pages().dup(), offset, None)?;
|
||||
let mut iter = ExfatDentryIterator::new(self.page_cache.pages(), offset, None)?;
|
||||
|
||||
let mut dir_read = 0;
|
||||
let mut current_off = offset;
|
||||
|
|
@ -828,7 +827,7 @@ impl ExfatInode {
|
|||
let inner = self.inner.upread();
|
||||
|
||||
let dentry_iterator =
|
||||
ExfatDentryIterator::new(inner.page_cache.pages().dup(), 0, Some(inner.size))?;
|
||||
ExfatDentryIterator::new(inner.page_cache.pages(), 0, Some(inner.size))?;
|
||||
|
||||
let mut contiguous_unused = 0;
|
||||
let mut entry_id = 0;
|
||||
|
|
@ -1225,8 +1224,8 @@ impl Inode for ExfatInode {
|
|||
self.inner.read().fs()
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
Some(self.inner.read().page_cache.pages().dup())
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
Some(self.inner.read().page_cache.pages().clone())
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#![expect(unused_variables)]
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Full;
|
||||
|
||||
use super::{
|
||||
constants::UNICODE_SIZE,
|
||||
|
|
@ -33,7 +32,7 @@ impl ExfatUpcaseTable {
|
|||
|
||||
pub(super) fn load(
|
||||
fs_weak: Weak<ExfatFs>,
|
||||
root_page_cache: Vmo<Full>,
|
||||
root_page_cache: &Vmo,
|
||||
root_chain: ExfatChain,
|
||||
) -> Result<Self> {
|
||||
let dentry_iterator = ExfatDentryIterator::new(root_page_cache, 0, None)?;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
use core::time::Duration;
|
||||
|
||||
use aster_rights::Full;
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
ext2::{FilePerm, Inode as Ext2Inode},
|
||||
|
|
@ -91,7 +89,7 @@ impl Inode for Ext2Inode {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
Some(self.page_cache())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ impl Inode {
|
|||
self.fs.upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub fn page_cache(&self) -> Vmo<Full> {
|
||||
self.inner.read().page_cache.pages().dup()
|
||||
pub fn page_cache(&self) -> Arc<Vmo> {
|
||||
self.inner.read().page_cache.pages().clone()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> Metadata {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ pub(super) use aster_block::{
|
|||
id::Bid,
|
||||
BlockDevice, BLOCK_SIZE,
|
||||
};
|
||||
pub(super) use aster_rights::Full;
|
||||
pub(super) use ostd::{
|
||||
mm::{Frame, FrameAllocOptions, Segment, USegment, VmIo},
|
||||
sync::{RwMutex, RwMutexReadGuard, RwMutexWriteGuard},
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use core::{
|
|||
|
||||
use align_ext::AlignExt;
|
||||
use aster_block::BLOCK_SIZE;
|
||||
use aster_rights::Full;
|
||||
use hashbrown::HashSet;
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
use ostd::{
|
||||
|
|
@ -445,7 +444,7 @@ impl OverlayInode {
|
|||
self.type_
|
||||
}
|
||||
|
||||
pub fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
pub fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
let _ = self.get_top_valid_inode().page_cache()?;
|
||||
// Do copy-up for the potential memory mapping operations
|
||||
let upper = self.build_upper_recursively_if_needed().unwrap();
|
||||
|
|
@ -928,7 +927,7 @@ impl Inode for OverlayInode {
|
|||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn page_cache(&self) -> Option<Vmo<Full>>;
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>>;
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize>;
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ use core::{
|
|||
|
||||
use align_ext::AlignExt;
|
||||
use aster_block::bio::BioWaiter;
|
||||
use aster_rights::Full;
|
||||
use aster_util::slot_vec::SlotVec;
|
||||
use hashbrown::HashMap;
|
||||
use ostd::{
|
||||
mm::{io_util::HasVmReaderWriter, HasSize, VmIo},
|
||||
mm::{io_util::HasVmReaderWriter, HasSize},
|
||||
sync::{PreemptDisabled, RwLockWriteGuard},
|
||||
};
|
||||
|
||||
|
|
@ -529,10 +528,10 @@ impl PageCacheBackend for RamInode {
|
|||
}
|
||||
|
||||
impl Inode for RamInode {
|
||||
fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
self.inner
|
||||
.as_file()
|
||||
.map(|page_cache| page_cache.pages().dup())
|
||||
.map(|page_cache| page_cache.pages().clone())
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
use core::{any::TypeId, time::Duration};
|
||||
|
||||
use aster_rights::Full;
|
||||
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
|
||||
use ostd::task::Task;
|
||||
|
||||
|
|
@ -292,7 +291,7 @@ pub trait Inode: Any + Sync + Send {
|
|||
|
||||
fn set_ctime(&self, time: Duration);
|
||||
|
||||
fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use core::{
|
|||
|
||||
use align_ext::AlignExt;
|
||||
use aster_block::bio::{BioStatus, BioWaiter};
|
||||
use aster_rights::Full;
|
||||
use lru::LruCache;
|
||||
use ostd::{
|
||||
impl_untyped_frame_meta_for,
|
||||
|
|
@ -22,7 +21,7 @@ use crate::{
|
|||
};
|
||||
|
||||
pub struct PageCache {
|
||||
pages: Vmo<Full>,
|
||||
pages: Arc<Vmo>,
|
||||
manager: Arc<PageCacheManager>,
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ impl PageCache {
|
|||
/// Creates an empty size page cache associated with a new backend.
|
||||
pub fn new(backend: Weak<dyn PageCacheBackend>) -> Result<Self> {
|
||||
let manager = Arc::new(PageCacheManager::new(backend));
|
||||
let pages = VmoOptions::<Full>::new(0)
|
||||
let pages = VmoOptions::new(0)
|
||||
.flags(VmoFlags::RESIZABLE)
|
||||
.pager(manager.clone())
|
||||
.alloc()?;
|
||||
|
|
@ -43,7 +42,7 @@ impl PageCache {
|
|||
/// This size usually corresponds to the size of the backend.
|
||||
pub fn with_capacity(capacity: usize, backend: Weak<dyn PageCacheBackend>) -> Result<Self> {
|
||||
let manager = Arc::new(PageCacheManager::new(backend));
|
||||
let pages = VmoOptions::<Full>::new(capacity)
|
||||
let pages = VmoOptions::new(capacity)
|
||||
.flags(VmoFlags::RESIZABLE)
|
||||
.pager(manager.clone())
|
||||
.alloc()?;
|
||||
|
|
@ -51,9 +50,7 @@ impl PageCache {
|
|||
}
|
||||
|
||||
/// Returns the Vmo object.
|
||||
// TODO: The capability is too high,restrict it to eliminate the possibility of misuse.
|
||||
// For example, the `resize` api should be forbidded.
|
||||
pub fn pages(&self) -> &Vmo<Full> {
|
||||
pub fn pages(&self) -> &Arc<Vmo> {
|
||||
&self.pages
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
|||
unimplemented!("fs() method should be implemented by the concrete inode type");
|
||||
}
|
||||
|
||||
default fn page_cache(&self) -> Option<crate::vm::vmo::Vmo<aster_rights::Full>> {
|
||||
default fn page_cache(&self) -> Option<Arc<crate::vm::vmo::Vmo>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use core::{
|
|||
};
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Full;
|
||||
use ostd::mm::{VmIo, MAX_USERSPACE_VADDR};
|
||||
|
||||
use self::aux_vec::{AuxKey, AuxVec};
|
||||
|
|
@ -29,7 +28,7 @@ use crate::{
|
|||
vm::{
|
||||
perms::VmPerms,
|
||||
vmar::Vmar,
|
||||
vmo::{Vmo, VmoOptions, VmoRightsOp},
|
||||
vmo::{Vmo, VmoOptions},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -173,7 +172,7 @@ impl InitStack {
|
|||
self.set_uninitialized();
|
||||
|
||||
let vmo = {
|
||||
let vmo_options = VmoOptions::<Full>::new(self.max_size);
|
||||
let vmo_options = VmoOptions::new(self.max_size);
|
||||
vmo_options.alloc()?
|
||||
};
|
||||
let vmar_map_options = {
|
||||
|
|
@ -182,7 +181,7 @@ impl InitStack {
|
|||
debug_assert!(map_addr % PAGE_SIZE == 0);
|
||||
vmar.new_map(self.max_size, perms)?
|
||||
.offset(map_addr)
|
||||
.vmo(vmo.dup().to_dyn())
|
||||
.vmo(vmo.clone())
|
||||
};
|
||||
vmar_map_options.build()?;
|
||||
|
||||
|
|
@ -231,7 +230,7 @@ impl InitStack {
|
|||
/// A writer to initialize the content of an `InitStack`.
|
||||
struct InitStackWriter<'a> {
|
||||
pos: &'a AtomicUsize,
|
||||
vmo: Vmo<Full>,
|
||||
vmo: Arc<Vmo>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
auxvec: AuxVec,
|
||||
|
|
|
|||
|
|
@ -20,12 +20,7 @@ use crate::{
|
|||
},
|
||||
prelude::*,
|
||||
process::process_vm::{AuxKey, AuxVec},
|
||||
vm::{
|
||||
perms::VmPerms,
|
||||
util::duplicate_frame,
|
||||
vmar::Vmar,
|
||||
vmo::{CommitFlags, VmoRightsOp},
|
||||
},
|
||||
vm::{perms::VmPerms, util::duplicate_frame, vmar::Vmar, vmo::CommitFlags},
|
||||
};
|
||||
|
||||
/// Loads elf to the process VMAR.
|
||||
|
|
@ -324,14 +319,10 @@ fn map_segment_vmo(
|
|||
debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE);
|
||||
let segment_vmo = {
|
||||
let inode = elf_file.inode();
|
||||
inode
|
||||
.page_cache()
|
||||
.ok_or(Error::with_message(
|
||||
Errno::ENOENT,
|
||||
"executable has no page cache",
|
||||
))?
|
||||
.to_dyn()
|
||||
.dup()?
|
||||
inode.page_cache().ok_or(Error::with_message(
|
||||
Errno::ENOENT,
|
||||
"executable has no page cache",
|
||||
))?
|
||||
};
|
||||
|
||||
let total_map_size = {
|
||||
|
|
@ -352,7 +343,7 @@ fn map_segment_vmo(
|
|||
if segment_size != 0 {
|
||||
let mut vm_map_options = vmar
|
||||
.new_map(segment_size, perms)?
|
||||
.vmo(segment_vmo.dup()?)
|
||||
.vmo(segment_vmo.clone())
|
||||
.vmo_offset(segment_offset)
|
||||
.can_overwrite(true);
|
||||
vm_map_options = vm_map_options.offset(offset).handle_page_faults_around();
|
||||
|
|
@ -498,7 +489,7 @@ fn map_vdso_to_vmar(vmar: &Vmar) -> Option<Vaddr> {
|
|||
let options = vmar
|
||||
.new_map(VDSO_VMO_LAYOUT.size, VmPerms::empty())
|
||||
.unwrap()
|
||||
.vmo(vdso_vmo.dup().unwrap());
|
||||
.vmo(vdso_vmo);
|
||||
|
||||
let vdso_vmo_base = options.build().unwrap();
|
||||
let vdso_data_base = vdso_vmo_base + VDSO_VMO_LAYOUT.data_segment_offset;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
//! This mod defines mmap flags and the handler to syscall mmap
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Rights;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
|
|
@ -116,7 +115,7 @@ fn do_sys_mmap(
|
|||
// Anonymous shared mapping should share the same memory pages.
|
||||
if option.typ() == MMapType::Shared {
|
||||
let shared_vmo = {
|
||||
let vmo_options: VmoOptions<Rights> = VmoOptions::new(len);
|
||||
let vmo_options = VmoOptions::new(len);
|
||||
vmo_options.alloc()?
|
||||
};
|
||||
options = options.vmo(shared_vmo);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
use alloc::sync::Arc;
|
||||
use core::{mem::ManuallyDrop, time::Duration};
|
||||
|
||||
use aster_rights::Rights;
|
||||
use aster_time::{read_monotonic_time, Instant};
|
||||
use aster_util::coeff::Coeff;
|
||||
use ostd::{
|
||||
|
|
@ -238,7 +237,7 @@ impl Vdso {
|
|||
vdso_data.init();
|
||||
|
||||
let (vdso_vmo, data_frame) = {
|
||||
let vmo_options = VmoOptions::<Rights>::new(VDSO_VMO_LAYOUT.size);
|
||||
let vmo_options = VmoOptions::new(VDSO_VMO_LAYOUT.size);
|
||||
let vdso_vmo = vmo_options.alloc().unwrap();
|
||||
// Write vDSO data to vDSO VMO.
|
||||
vdso_vmo
|
||||
|
|
@ -259,7 +258,7 @@ impl Vdso {
|
|||
|
||||
Self {
|
||||
data: SpinLock::new(vdso_data),
|
||||
vmo: Arc::new(vdso_vmo),
|
||||
vmo: vdso_vmo,
|
||||
data_frame,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ mod vm_mapping;
|
|||
use core::{array, num::NonZeroUsize, ops::Range};
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Rights;
|
||||
use aster_util::per_cpu_counter::PerCpuCounter;
|
||||
use ostd::{
|
||||
cpu::CpuId,
|
||||
|
|
@ -32,10 +31,7 @@ use crate::{
|
|||
prelude::*,
|
||||
process::{Process, ProcessVm, ResourceType},
|
||||
thread::exception::PageFaultInfo,
|
||||
vm::{
|
||||
perms::VmPerms,
|
||||
vmo::{Vmo, VmoRightsOp},
|
||||
},
|
||||
vm::{perms::VmPerms, vmo::Vmo},
|
||||
};
|
||||
|
||||
/// Virtual Memory Address Regions (VMARs) are a type of capability that manages
|
||||
|
|
@ -71,13 +67,12 @@ impl Vmar {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use aster_rights::Rights;
|
||||
/// use ostd::mm::PAGE_SIZE;
|
||||
///
|
||||
/// use crate::vm::{perms::VmPerms, vmar::Vmar, vmo::VmoOptions};
|
||||
///
|
||||
/// let vmar = Vmar::new();
|
||||
/// let vmo = VmoOptions::<Rights>::new(10 * PAGE_SIZE).alloc().unwrap();
|
||||
/// let vmo = VmoOptions::new(10 * PAGE_SIZE).alloc().unwrap();
|
||||
/// let target_vaddr = 0x1234000;
|
||||
/// let real_vaddr = vmar
|
||||
/// // Create a 4 * PAGE_SIZE bytes, read-only mapping
|
||||
|
|
@ -95,7 +90,7 @@ impl Vmar {
|
|||
/// ```
|
||||
///
|
||||
/// For more details on the available options, see `VmarMapOptions`.
|
||||
pub fn new_map(&self, size: usize, perms: VmPerms) -> Result<VmarMapOptions<Rights>> {
|
||||
pub fn new_map(&self, size: usize, perms: VmPerms) -> Result<VmarMapOptions> {
|
||||
Ok(VmarMapOptions::new(self, size, perms))
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +216,7 @@ impl Vmar {
|
|||
let base = vm_mapping.map_to_addr();
|
||||
|
||||
// Clone the `VmMapping` to the new VMAR.
|
||||
let new_mapping = vm_mapping.new_fork()?;
|
||||
let new_mapping = vm_mapping.new_fork();
|
||||
new_inner.insert_without_try_merge(new_mapping);
|
||||
|
||||
// Protect the mapping and copy to the new page table for COW.
|
||||
|
|
@ -416,7 +411,7 @@ impl Vmar {
|
|||
old_mapping
|
||||
};
|
||||
// Note that we have ensured that `new_size >= old_size` at the beginning.
|
||||
let new_mapping = old_mapping.clone_for_remap_at(new_range.start).unwrap();
|
||||
let new_mapping = old_mapping.clone_for_remap_at(new_range.start);
|
||||
inner.insert_try_merge(new_mapping.enlarge(new_size - old_size));
|
||||
|
||||
let preempt_guard = disable_preempt();
|
||||
|
|
@ -953,9 +948,9 @@ fn cow_copy_pt(src: &mut CursorMut<'_>, dst: &mut CursorMut<'_>, size: usize) ->
|
|||
/// Options for creating a new mapping. The mapping is not allowed to overlap
|
||||
/// with any child VMARs. And unless specified otherwise, it is not allowed
|
||||
/// to overlap with any existing mapping, either.
|
||||
pub struct VmarMapOptions<'a, R> {
|
||||
pub struct VmarMapOptions<'a> {
|
||||
parent: &'a Vmar,
|
||||
vmo: Option<Vmo<R>>,
|
||||
vmo: Option<Arc<Vmo>>,
|
||||
mappable: Option<Mappable>,
|
||||
perms: VmPerms,
|
||||
may_perms: VmPerms,
|
||||
|
|
@ -970,13 +965,9 @@ pub struct VmarMapOptions<'a, R> {
|
|||
handle_page_faults_around: bool,
|
||||
}
|
||||
|
||||
impl<'a, R> VmarMapOptions<'a, R> {
|
||||
/// Creates a default set of options with the VMO and the memory access
|
||||
impl<'a> VmarMapOptions<'a> {
|
||||
/// Creates a default set of options with the size and the memory access
|
||||
/// permissions.
|
||||
///
|
||||
/// The VMO must have access rights that correspond to the memory
|
||||
/// access permissions. For example, if `perms` contains `VmPerms::Write`,
|
||||
/// then `vmo.rights()` should contain `Rights::WRITE`.
|
||||
pub fn new(parent: &'a Vmar, size: usize, perms: VmPerms) -> Self {
|
||||
Self {
|
||||
parent,
|
||||
|
|
@ -1026,7 +1017,7 @@ impl<'a, R> VmarMapOptions<'a, R> {
|
|||
/// # Panics
|
||||
///
|
||||
/// This function panics if a [`Mappable`] is already provided.
|
||||
pub fn vmo(mut self, vmo: Vmo<R>) -> Self {
|
||||
pub fn vmo(mut self, vmo: Arc<Vmo>) -> Self {
|
||||
if self.mappable.is_some() {
|
||||
panic!("Cannot set `vmo` when `mappable` is already set");
|
||||
}
|
||||
|
|
@ -1098,9 +1089,7 @@ impl<'a, R> VmarMapOptions<'a, R> {
|
|||
self.handle_page_faults_around = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl VmarMapOptions<'_, Rights> {
|
||||
/// Binds memory to map based on the [`Mappable`] enum.
|
||||
///
|
||||
/// This method accepts file-specific details, like a page cache (inode)
|
||||
|
|
@ -1119,24 +1108,14 @@ impl VmarMapOptions<'_, Rights> {
|
|||
|
||||
// Verify whether the page cache inode is valid.
|
||||
if let Mappable::Inode(ref inode) = mappable {
|
||||
self.vmo = Some(
|
||||
inode
|
||||
.page_cache()
|
||||
.expect("Map an inode without page cache")
|
||||
.to_dyn(),
|
||||
);
|
||||
self.vmo = Some(inode.page_cache().expect("Map an inode without page cache"));
|
||||
}
|
||||
|
||||
self.mappable = Some(mappable);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> VmarMapOptions<'_, R>
|
||||
where
|
||||
Vmo<R>: VmoRightsOp,
|
||||
{
|
||||
/// Creates the mapping and adds it to the parent VMAR.
|
||||
///
|
||||
/// All options will be checked at this point.
|
||||
|
|
@ -1206,15 +1185,14 @@ where
|
|||
Mappable::Inode(inode_handle) => {
|
||||
// Since `Mappable::Inode` is provided, it is
|
||||
// reasonable to assume that the VMO is provided.
|
||||
let mapped_mem =
|
||||
MappedMemory::Vmo(MappedVmo::new(vmo.unwrap().to_dyn(), vmo_offset));
|
||||
let mapped_mem = MappedMemory::Vmo(MappedVmo::new(vmo.unwrap(), vmo_offset));
|
||||
(mapped_mem, Some(inode_handle), None)
|
||||
}
|
||||
Mappable::IoMem(iomem) => (MappedMemory::Device, None, Some(iomem)),
|
||||
}
|
||||
} else if let Some(vmo) = vmo {
|
||||
(
|
||||
MappedMemory::Vmo(MappedVmo::new(vmo.to_dyn(), vmo_offset)),
|
||||
MappedMemory::Vmo(MappedVmo::new(vmo, vmo_offset)),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
|
|
@ -1271,11 +1249,10 @@ where
|
|||
return_errno_with_message!(Errno::EINVAL, "invalid offset");
|
||||
}
|
||||
}
|
||||
self.check_perms()?;
|
||||
Ok(())
|
||||
self.check_perms()
|
||||
}
|
||||
|
||||
/// Checks whether the permissions of the mapping is subset of vmo rights.
|
||||
/// Checks whether the permissions of the mapping is valid.
|
||||
fn check_perms(&self) -> Result<()> {
|
||||
if !VmPerms::ALL_MAY_PERMS.contains(self.may_perms)
|
||||
|| !VmPerms::ALL_PERMS.contains(self.perms)
|
||||
|
|
@ -1284,14 +1261,7 @@ where
|
|||
}
|
||||
|
||||
let vm_perms = self.perms | self.may_perms;
|
||||
vm_perms.check()?;
|
||||
|
||||
let Some(vmo) = &self.vmo else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let perm_rights = Rights::from(vm_perms);
|
||||
vmo.check_rights(perm_rights)
|
||||
vm_perms.check()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,18 +111,18 @@ impl VmMapping {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn new_fork(&self) -> Result<VmMapping> {
|
||||
Ok(VmMapping {
|
||||
mapped_mem: self.mapped_mem.dup()?,
|
||||
pub(super) fn new_fork(&self) -> VmMapping {
|
||||
VmMapping {
|
||||
mapped_mem: self.mapped_mem.dup(),
|
||||
inode: self.inode.clone(),
|
||||
..*self
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn clone_for_remap_at(&self, va: Vaddr) -> Result<VmMapping> {
|
||||
let mut vm_mapping = self.new_fork()?;
|
||||
pub(super) fn clone_for_remap_at(&self, va: Vaddr) -> VmMapping {
|
||||
let mut vm_mapping = self.new_fork();
|
||||
vm_mapping.map_to_addr = va;
|
||||
Ok(vm_mapping)
|
||||
vm_mapping
|
||||
}
|
||||
|
||||
/// Returns the mapping's start address.
|
||||
|
|
@ -506,13 +506,11 @@ impl VmMapping {
|
|||
debug_assert!(self.map_to_addr < at && at < self.map_end());
|
||||
debug_assert!(at % PAGE_SIZE == 0);
|
||||
|
||||
let (l_mapped_mem, r_mapped_mem) = match &self.mapped_mem {
|
||||
let (l_mapped_mem, r_mapped_mem) = match self.mapped_mem {
|
||||
MappedMemory::Vmo(vmo) => {
|
||||
let at_offset = vmo.offset() + (at - self.map_to_addr);
|
||||
(
|
||||
MappedMemory::Vmo(MappedVmo::new(vmo.vmo().dup()?, vmo.offset())),
|
||||
MappedMemory::Vmo(MappedVmo::new(vmo.vmo().dup()?, at_offset)),
|
||||
)
|
||||
let r_mapped_vmo = MappedVmo::new(vmo.vmo().clone(), at_offset);
|
||||
(MappedMemory::Vmo(vmo), MappedMemory::Vmo(r_mapped_vmo))
|
||||
}
|
||||
MappedMemory::Anonymous => {
|
||||
// For anonymous mappings, we create new anonymous mappings for the split parts
|
||||
|
|
@ -683,12 +681,12 @@ pub(super) enum MappedMemory {
|
|||
|
||||
impl MappedMemory {
|
||||
/// Duplicates the mapped memory capability.
|
||||
pub(super) fn dup(&self) -> Result<Self> {
|
||||
Ok(match self {
|
||||
pub(super) fn dup(&self) -> Self {
|
||||
match self {
|
||||
MappedMemory::Anonymous => MappedMemory::Anonymous,
|
||||
MappedMemory::Vmo(v) => MappedMemory::Vmo(v.dup()?),
|
||||
MappedMemory::Vmo(v) => MappedMemory::Vmo(v.dup()),
|
||||
MappedMemory::Device => MappedMemory::Device,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -696,14 +694,14 @@ impl MappedMemory {
|
|||
/// that need to be provided to mappings from the VMO.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct MappedVmo {
|
||||
vmo: Vmo,
|
||||
vmo: Arc<Vmo>,
|
||||
/// Represents the mapped offset in the VMO for the mapping.
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl MappedVmo {
|
||||
/// Creates a `MappedVmo` used for the mapping.
|
||||
pub(super) fn new(vmo: Vmo, offset: usize) -> Self {
|
||||
pub(super) fn new(vmo: Arc<Vmo>, offset: usize) -> Self {
|
||||
Self { vmo, offset }
|
||||
}
|
||||
|
||||
|
|
@ -758,7 +756,7 @@ impl MappedVmo {
|
|||
}
|
||||
|
||||
/// Gets a reference to the underlying VMO.
|
||||
pub fn vmo(&self) -> &Vmo {
|
||||
pub fn vmo(&self) -> &Arc<Vmo> {
|
||||
&self.vmo
|
||||
}
|
||||
|
||||
|
|
@ -768,11 +766,11 @@ impl MappedVmo {
|
|||
}
|
||||
|
||||
/// Duplicates the capability.
|
||||
pub fn dup(&self) -> Result<Self> {
|
||||
Ok(Self {
|
||||
vmo: self.vmo.dup()?,
|
||||
pub fn dup(&self) -> Self {
|
||||
Self {
|
||||
vmo: self.vmo.clone(),
|
||||
offset: self.offset,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -802,13 +800,13 @@ fn try_merge(left: &VmMapping, right: &VmMapping) -> Option<VmMapping> {
|
|||
let l_vmo = l_vmo_obj.vmo();
|
||||
let r_vmo = r_vmo_obj.vmo();
|
||||
|
||||
if Arc::ptr_eq(&l_vmo.0, &r_vmo.0) {
|
||||
if Arc::ptr_eq(l_vmo, r_vmo) {
|
||||
let is_offset_contiguous =
|
||||
l_vmo_obj.offset() + left.map_size() == r_vmo_obj.offset();
|
||||
if !is_offset_contiguous {
|
||||
return None;
|
||||
}
|
||||
MappedMemory::Vmo(l_vmo_obj.dup().ok()?)
|
||||
MappedMemory::Vmo(l_vmo_obj.dup())
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,174 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
use aster_rights::{Rights, TRights};
|
||||
use ostd::mm::{UFrame, VmIo, VmIoFill};
|
||||
|
||||
use super::{CommitFlags, Vmo, VmoCommitError, VmoRightsOp};
|
||||
use crate::prelude::*;
|
||||
|
||||
impl Vmo<Rights> {
|
||||
/// Commits a page at specific offset.
|
||||
///
|
||||
/// If the commit operation needs to perform I/O, it will return a [`VmoCommitError::NeedIo`].
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub fn try_commit_page(&self, offset: usize) -> core::result::Result<UFrame, VmoCommitError> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.try_commit_page(offset)
|
||||
}
|
||||
|
||||
/// Commits a page at a specific page index.
|
||||
///
|
||||
/// This method may involve I/O operations if the VMO needs to fetch
|
||||
/// a page from the underlying page cache.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub fn commit_on(&self, page_idx: usize, commit_flags: CommitFlags) -> Result<UFrame> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.commit_on(page_idx, commit_flags)
|
||||
}
|
||||
|
||||
/// Traverses the indices within a specified range of a VMO sequentially.
|
||||
///
|
||||
/// For each index position, you have the option to commit the page as well as
|
||||
/// perform other operations.
|
||||
///
|
||||
/// Once a commit operation needs to perform I/O, it will return a [`VmoCommitError::NeedIo`].
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub(in crate::vm) fn try_operate_on_range<F>(
|
||||
&self,
|
||||
range: &Range<usize>,
|
||||
operate: F,
|
||||
) -> core::result::Result<(), VmoCommitError>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut dyn FnMut() -> core::result::Result<UFrame, VmoCommitError>,
|
||||
) -> core::result::Result<(), VmoCommitError>,
|
||||
{
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.try_operate_on_range(range, operate)
|
||||
}
|
||||
|
||||
/// Decommits the pages specified in the range (in bytes).
|
||||
///
|
||||
/// The range must be within the size of the VMO.
|
||||
///
|
||||
/// The start and end addresses will be rounded down and up to page boundaries.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub fn decommit(&self, range: Range<usize>) -> Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.decommit(range)
|
||||
}
|
||||
|
||||
/// Resizes the VMO by giving a new size.
|
||||
///
|
||||
/// The VMO must be resizable.
|
||||
///
|
||||
/// The new size will be rounded up to page boundaries.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub fn resize(&self, new_size: usize) -> Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.resize(new_size)
|
||||
}
|
||||
|
||||
/// Clears the specified range by writing zeros.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
pub fn clear(&self, range: Range<usize>) -> Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.clear(range)
|
||||
}
|
||||
|
||||
/// Duplicates the capability.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Dup right.
|
||||
pub fn dup(&self) -> Result<Self> {
|
||||
self.check_rights(Rights::DUP)?;
|
||||
Ok(Self(self.0.clone(), 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: UFrame, page_idx: usize) -> Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.replace(page, page_idx)
|
||||
}
|
||||
|
||||
/// Restricts the access rights given the mask.
|
||||
pub fn restrict(mut self, mask: Rights) -> Self {
|
||||
self.1 |= mask;
|
||||
self
|
||||
}
|
||||
|
||||
/// Converts to a static capability.
|
||||
#[expect(clippy::wrong_self_convention)]
|
||||
pub fn to_static<R1: TRights>(self) -> Result<Vmo<R1>> {
|
||||
self.check_rights(Rights::from_bits(R1::BITS).ok_or(Error::new(Errno::EINVAL))?)?;
|
||||
Ok(Vmo(self.0, R1::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl VmIo for Vmo<Rights> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
|
||||
self.check_rights(Rights::READ)?;
|
||||
self.0.read(offset, writer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.write(offset, reader)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VmIoFill for Vmo<Rights> {
|
||||
fn fill_zeros(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
) -> core::result::Result<(), (ostd::Error, usize)> {
|
||||
// TODO: Support efficient `fill_zeros()`.
|
||||
for i in 0..len {
|
||||
match self.write_slice(offset + i, &[0u8]) {
|
||||
Ok(()) => continue,
|
||||
Err(err) => return Err((err, i)),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VmoRightsOp for Vmo<Rights> {
|
||||
fn rights(&self) -> Rights {
|
||||
self.1
|
||||
}
|
||||
|
||||
/// Converts to a dynamic capability.
|
||||
fn to_dyn(self) -> Vmo<Rights> {
|
||||
let rights = self.rights();
|
||||
Vmo(self.0, rights)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,19 +11,18 @@ use core::{
|
|||
};
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::Rights;
|
||||
use ostd::{
|
||||
mm::{io_util::HasVmReaderWriter, FrameAllocOptions, UFrame, VmReader, VmWriter},
|
||||
mm::{
|
||||
io_util::HasVmReaderWriter, FrameAllocOptions, UFrame, VmIo, VmIoFill, VmReader, VmWriter,
|
||||
},
|
||||
task::disable_preempt,
|
||||
};
|
||||
use xarray::{Cursor, LockedXArray, XArray};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
mod dyn_cap;
|
||||
mod options;
|
||||
mod pager;
|
||||
mod static_cap;
|
||||
|
||||
pub use options::VmoOptions;
|
||||
pub use pager::Pager;
|
||||
|
|
@ -31,14 +30,17 @@ pub use pager::Pager;
|
|||
/// Virtual Memory Objects (VMOs) are a type of capability that represents a
|
||||
/// range of memory pages.
|
||||
///
|
||||
/// Broadly speaking, there are two types of VMO:
|
||||
/// 1. File-backed VMO: the VMO backed by a file and resides in the page cache,
|
||||
/// 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`.
|
||||
///
|
||||
/// # Features
|
||||
///
|
||||
/// * **I/O interface.** A VMO provides read and write methods to access the
|
||||
/// memory pages that it contain.
|
||||
/// * **On-demand paging.** The memory pages of a VMO (except for _contiguous_
|
||||
/// VMOs) are allocated lazily when the page is first accessed.
|
||||
/// * **Access control.** As capabilities, VMOs restrict the
|
||||
/// accessible range of memory and the allowed I/O operations.
|
||||
/// * **Device driver support.** If specified upon creation, VMOs will be
|
||||
/// backed by physically contiguous memory pages starting at a target address.
|
||||
/// * **File system support.** By default, a VMO's memory pages are initially
|
||||
|
|
@ -47,22 +49,6 @@ pub use pager::Pager;
|
|||
/// With this pager mechanism, file systems can easily implement page caches
|
||||
/// with VMOs by attaching the VMOs to pagers backed by inodes.
|
||||
///
|
||||
/// # Capabilities
|
||||
///
|
||||
/// As a capability, each VMO is associated with a set of access rights,
|
||||
/// whose semantics are explained below.
|
||||
///
|
||||
/// * The Dup right allows duplicating a VMO and creating children out of
|
||||
/// a VMO.
|
||||
/// * The Read, Write, Exec rights allow creating memory mappings with
|
||||
/// readable, writable, and executable access permissions, respectively.
|
||||
/// * The Read and Write rights allow the VMO to be read from and written to
|
||||
/// directly.
|
||||
/// * The Write right allows resizing a resizable VMO.
|
||||
///
|
||||
/// VMOs are implemented with two flavors of capabilities:
|
||||
/// the dynamic one (`Vmo<Rights>`) and the static one (`Vmo<R: TRights>).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// For creating root VMOs, see [`VmoOptions`].
|
||||
|
|
@ -74,27 +60,28 @@ pub use pager::Pager;
|
|||
/// Compared with `UFrame`,
|
||||
/// `Vmo` is easier to use (by offering more powerful APIs) and
|
||||
/// harder to misuse (thanks to its nature of being capability).
|
||||
#[derive(Debug)]
|
||||
pub struct Vmo<R = Rights>(pub(super) Arc<Vmo_>, R);
|
||||
pub struct Vmo {
|
||||
pager: Option<Arc<dyn Pager>>,
|
||||
/// Flags
|
||||
flags: VmoFlags,
|
||||
/// The virtual pages where the VMO resides.
|
||||
pages: XArray<UFrame>,
|
||||
/// The size of the VMO.
|
||||
///
|
||||
/// Note: This size may not necessarily match the size of the `pages`, but it is
|
||||
/// required here that modifications to the size can only be made after locking
|
||||
/// the [`XArray`] in the `pages` field. Therefore, the size read after locking the
|
||||
/// `pages` will be the latest size.
|
||||
size: AtomicUsize,
|
||||
}
|
||||
|
||||
/// Functions exist both for static capbility and dynamic capability
|
||||
pub trait VmoRightsOp {
|
||||
/// Returns the access rights.
|
||||
fn rights(&self) -> Rights;
|
||||
|
||||
/// Checks whether current rights meet the input `rights`.
|
||||
fn check_rights(&self, rights: Rights) -> Result<()> {
|
||||
if self.rights().contains(rights) {
|
||||
Ok(())
|
||||
} else {
|
||||
return_errno_with_message!(Errno::EACCES, "VMO rights are insufficient");
|
||||
}
|
||||
impl Debug for Vmo {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Vmo")
|
||||
.field("flags", &self.flags)
|
||||
.field("size", &self.size())
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Converts to a dynamic capability.
|
||||
fn to_dyn(self) -> Vmo<Rights>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
@ -136,36 +123,6 @@ impl From<ostd::Error> for VmoCommitError {
|
|||
}
|
||||
}
|
||||
|
||||
/// `Vmo_` is the structure that actually manages the content of VMO.
|
||||
///
|
||||
/// Broadly speaking, there are two types of VMO:
|
||||
/// 1. File-backed VMO: the VMO backed by a file and resides in the page cache,
|
||||
/// 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`.
|
||||
pub(super) struct Vmo_ {
|
||||
pager: Option<Arc<dyn Pager>>,
|
||||
/// Flags
|
||||
flags: VmoFlags,
|
||||
/// The virtual pages where the VMO resides.
|
||||
pages: XArray<UFrame>,
|
||||
/// The size of the VMO.
|
||||
///
|
||||
/// Note: This size may not necessarily match the size of the `pages`, but it is
|
||||
/// required here that modifications to the size can only be made after locking
|
||||
/// the [`XArray`] in the `pages` field. Therefore, the size read after locking the
|
||||
/// `pages` will be the latest size.
|
||||
size: AtomicUsize,
|
||||
}
|
||||
|
||||
impl Debug for Vmo_ {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Vmo_")
|
||||
.field("flags", &self.flags)
|
||||
.field("size", &self.size())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Commit Flags.
|
||||
pub struct CommitFlags: u8 {
|
||||
|
|
@ -181,7 +138,7 @@ impl CommitFlags {
|
|||
}
|
||||
}
|
||||
|
||||
impl Vmo_ {
|
||||
impl Vmo {
|
||||
/// Prepares a new `UFrame` for the target index in pages, returns this new frame.
|
||||
///
|
||||
/// This operation may involve I/O operations if the VMO is backed by a pager.
|
||||
|
|
@ -324,6 +281,10 @@ impl Vmo_ {
|
|||
}
|
||||
|
||||
/// Decommits a range of pages in the VMO.
|
||||
///
|
||||
/// The range must be within the size of the VMO.
|
||||
///
|
||||
/// The start and end addresses will be rounded down and up to page boundaries.
|
||||
pub fn decommit(&self, range: Range<usize>) -> Result<()> {
|
||||
let locked_pages = self.pages.lock();
|
||||
if range.end > self.size() {
|
||||
|
|
@ -401,7 +362,7 @@ impl Vmo_ {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears the target range in current VMO.
|
||||
/// Clears the target range in current VMO by writing zeros.
|
||||
pub fn clear(&self, range: Range<usize>) -> Result<()> {
|
||||
let buffer = vec![0u8; range.end - range.start];
|
||||
let mut reader = VmReader::from(buffer.as_slice()).to_fallible();
|
||||
|
|
@ -415,6 +376,10 @@ impl Vmo_ {
|
|||
}
|
||||
|
||||
/// Resizes current VMO to target size.
|
||||
///
|
||||
/// The VMO must be resizable.
|
||||
///
|
||||
/// The new size will be rounded up to page boundaries.
|
||||
pub fn resize(&self, new_size: usize) -> Result<()> {
|
||||
assert!(self.flags.contains(VmoFlags::RESIZABLE));
|
||||
let new_size = new_size.align_up(PAGE_SIZE);
|
||||
|
|
@ -473,6 +438,7 @@ impl Vmo_ {
|
|||
self.flags
|
||||
}
|
||||
|
||||
/// Replaces the page at the `page_idx` in the VMO with the input `page`.
|
||||
fn replace(&self, page: UFrame, page_idx: usize) -> Result<()> {
|
||||
let mut locked_pages = self.pages.lock();
|
||||
if page_idx >= self.size() / PAGE_SIZE {
|
||||
|
|
@ -484,15 +450,32 @@ impl Vmo_ {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> Vmo<R> {
|
||||
/// Returns the size (in bytes) of a VMO.
|
||||
pub fn size(&self) -> usize {
|
||||
self.0.size()
|
||||
impl VmIo for Vmo {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
|
||||
self.read(offset, writer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the flags of a VMO.
|
||||
pub fn flags(&self) -> VmoFlags {
|
||||
self.0.flags()
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
|
||||
self.write(offset, reader)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VmIoFill for Vmo {
|
||||
fn fill_zeros(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
) -> core::result::Result<(), (ostd::Error, usize)> {
|
||||
// TODO: Support efficient `fill_zeros()`.
|
||||
for i in 0..len {
|
||||
match self.write_slice(offset + i, &[0u8]) {
|
||||
Ok(()) => continue,
|
||||
Err(err) => return Err((err, i)),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,21 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![expect(unused_variables)]
|
||||
|
||||
//! Options for allocating root and child VMOs.
|
||||
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_rights::{Rights, TRightSet, TRights};
|
||||
use ostd::mm::{FrameAllocOptions, UFrame, USegment};
|
||||
use xarray::XArray;
|
||||
|
||||
use super::{Pager, Vmo, VmoFlags};
|
||||
use crate::{prelude::*, vm::vmo::Vmo_};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Options for allocating a root VMO.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Creating a VMO as a _dynamic_ capability with full access rights:
|
||||
/// Creating a VMO:
|
||||
/// ```
|
||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions};
|
||||
///
|
||||
|
|
@ -27,16 +24,6 @@ use crate::{prelude::*, vm::vmo::Vmo_};
|
|||
/// .unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// Creating a VMO as a _static_ capability with all access rights:
|
||||
/// ```
|
||||
/// use aster_nix::prelude::*;
|
||||
/// use aster_nix::vm::{PAGE_SIZE, VmoOptions};
|
||||
///
|
||||
/// let vmo = VmoOptions::<Full>::new(PAGE_SIZE)
|
||||
/// .alloc()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// Creating a resizable VMO backed by 10 memory pages that may not be
|
||||
/// physically contiguous:
|
||||
///
|
||||
|
|
@ -48,14 +35,13 @@ use crate::{prelude::*, vm::vmo::Vmo_};
|
|||
/// .alloc()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
pub struct VmoOptions<R = Rights> {
|
||||
pub struct VmoOptions {
|
||||
size: usize,
|
||||
flags: VmoFlags,
|
||||
rights: Option<R>,
|
||||
pager: Option<Arc<dyn Pager>>,
|
||||
}
|
||||
|
||||
impl<R> VmoOptions<R> {
|
||||
impl VmoOptions {
|
||||
/// Creates a default set of options with the specified size of the VMO
|
||||
/// (in bytes).
|
||||
///
|
||||
|
|
@ -64,7 +50,6 @@ impl<R> VmoOptions<R> {
|
|||
Self {
|
||||
size,
|
||||
flags: VmoFlags::empty(),
|
||||
rights: None,
|
||||
pager: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -86,44 +71,21 @@ impl<R> VmoOptions<R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl VmoOptions<Rights> {
|
||||
impl VmoOptions {
|
||||
/// Allocates the VMO according to the specified options.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The VMO is initially assigned full access rights.
|
||||
pub fn alloc(self) -> Result<Vmo<Rights>> {
|
||||
pub fn alloc(self) -> Result<Arc<Vmo>> {
|
||||
let VmoOptions {
|
||||
size, flags, pager, ..
|
||||
} = self;
|
||||
let vmo_ = alloc_vmo_(size, flags, pager)?;
|
||||
Ok(Vmo(Arc::new(vmo_), Rights::all()))
|
||||
let vmo = alloc_vmo(size, flags, pager)?;
|
||||
Ok(Arc::new(vmo))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TRights> VmoOptions<TRightSet<R>> {
|
||||
/// Allocates the VMO according to the specified options.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The VMO is initially assigned the access rights represented
|
||||
/// by `R: TRights`.
|
||||
pub fn alloc(self) -> Result<Vmo<TRightSet<R>>> {
|
||||
let VmoOptions {
|
||||
size,
|
||||
flags,
|
||||
rights,
|
||||
pager,
|
||||
} = self;
|
||||
let vmo_ = alloc_vmo_(size, flags, pager)?;
|
||||
Ok(Vmo(Arc::new(vmo_), TRightSet(R::new())))
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_vmo_(size: usize, flags: VmoFlags, pager: Option<Arc<dyn Pager>>) -> Result<Vmo_> {
|
||||
fn alloc_vmo(size: usize, flags: VmoFlags, pager: Option<Arc<dyn Pager>>) -> Result<Vmo> {
|
||||
let size = size.align_up(PAGE_SIZE);
|
||||
let pages = committed_pages_if_continuous(flags, size)?;
|
||||
Ok(Vmo_ {
|
||||
Ok(Vmo {
|
||||
pager,
|
||||
flags,
|
||||
pages,
|
||||
|
|
@ -153,14 +115,13 @@ fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<
|
|||
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
use aster_rights::Full;
|
||||
use ostd::{mm::VmIo, prelude::*};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[ktest]
|
||||
fn alloc_vmo() {
|
||||
let vmo = VmoOptions::<Full>::new(PAGE_SIZE).alloc().unwrap();
|
||||
let vmo = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
||||
assert_eq!(vmo.size(), PAGE_SIZE);
|
||||
// the vmo is zeroed once allocated
|
||||
assert_eq!(vmo.read_val::<usize>(0).unwrap(), 0);
|
||||
|
|
@ -168,7 +129,7 @@ mod test {
|
|||
|
||||
#[ktest]
|
||||
fn alloc_continuous_vmo() {
|
||||
let vmo = VmoOptions::<Full>::new(10 * PAGE_SIZE)
|
||||
let vmo = VmoOptions::new(10 * PAGE_SIZE)
|
||||
.flags(VmoFlags::CONTIGUOUS)
|
||||
.alloc()
|
||||
.unwrap();
|
||||
|
|
@ -177,7 +138,7 @@ mod test {
|
|||
|
||||
#[ktest]
|
||||
fn write_and_read() {
|
||||
let vmo = VmoOptions::<Full>::new(PAGE_SIZE).alloc().unwrap();
|
||||
let vmo = VmoOptions::new(PAGE_SIZE).alloc().unwrap();
|
||||
let val = 42u8;
|
||||
// write val
|
||||
vmo.write_val(111, &val).unwrap();
|
||||
|
|
@ -191,7 +152,7 @@ mod test {
|
|||
|
||||
#[ktest]
|
||||
fn resize() {
|
||||
let vmo = VmoOptions::<Full>::new(PAGE_SIZE)
|
||||
let vmo = VmoOptions::new(PAGE_SIZE)
|
||||
.flags(VmoFlags::RESIZABLE)
|
||||
.alloc()
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
use aster_rights::{Dup, Rights, TRightSet, TRights, Write};
|
||||
use aster_rights_proc::require;
|
||||
use ostd::mm::{UFrame, VmIo, VmIoFill};
|
||||
|
||||
use super::{CommitFlags, Vmo, VmoCommitError, VmoRightsOp};
|
||||
use crate::prelude::*;
|
||||
|
||||
impl<R: TRights> Vmo<TRightSet<R>> {
|
||||
/// Commits a page at specific offset.
|
||||
///
|
||||
/// If the commit operation needs to perform I/O, it will return a [`VmoCommitError::NeedIo`].
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub fn try_commit_page(&self, offset: usize) -> core::result::Result<UFrame, VmoCommitError> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.try_commit_page(offset)
|
||||
}
|
||||
|
||||
/// Commits a page at a specific page index.
|
||||
///
|
||||
/// This method may involve I/O operations if the VMO needs to fetch
|
||||
/// a page from the underlying page cache.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub fn commit_on(&self, page_idx: usize, commit_flags: CommitFlags) -> Result<UFrame> {
|
||||
self.0.commit_on(page_idx, commit_flags)
|
||||
}
|
||||
|
||||
/// Traverses the indices within a specified range of a VMO sequentially.
|
||||
///
|
||||
/// For each index position, you have the option to commit the page as well as
|
||||
/// perform other operations.
|
||||
///
|
||||
/// Once a commit operation needs to perform I/O, it will return a [`VmoCommitError::NeedIo`].
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub(in crate::vm) fn try_operate_on_range<F>(
|
||||
&self,
|
||||
range: &Range<usize>,
|
||||
operate: F,
|
||||
) -> core::result::Result<(), VmoCommitError>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut dyn FnMut() -> core::result::Result<UFrame, VmoCommitError>,
|
||||
) -> core::result::Result<(), VmoCommitError>,
|
||||
{
|
||||
self.0.try_operate_on_range(range, operate)
|
||||
}
|
||||
|
||||
/// Decommits the pages specified in the range (in bytes).
|
||||
///
|
||||
/// The range must be within the size of the VMO.
|
||||
///
|
||||
/// The start and end addresses will be rounded down and up to page boundaries.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub fn decommit(&self, range: Range<usize>) -> Result<()> {
|
||||
self.0.decommit(range)
|
||||
}
|
||||
|
||||
/// Resize the VMO by giving a new size.
|
||||
///
|
||||
/// The VMO must be resizable.
|
||||
///
|
||||
/// The new size will be rounded up to page boundaries.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub fn resize(&self, new_size: usize) -> Result<()> {
|
||||
self.0.resize(new_size)
|
||||
}
|
||||
|
||||
/// Clear the specified range by writing zeros.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Write right.
|
||||
#[require(R > Write)]
|
||||
pub fn clear(&self, range: Range<usize>) -> Result<()> {
|
||||
self.0.clear(range)
|
||||
}
|
||||
|
||||
/// Duplicate the capability.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Dup right.
|
||||
#[require(R > Dup)]
|
||||
pub fn dup(&self) -> Self {
|
||||
Vmo(self.0.clone(), 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: UFrame, page_idx: usize) -> Result<()> {
|
||||
self.0.replace(page, page_idx)
|
||||
}
|
||||
|
||||
/// Strict the access rights.
|
||||
#[require(R > R1)]
|
||||
pub fn restrict<R1: TRights>(self) -> Vmo<TRightSet<R1>> {
|
||||
Vmo(self.0, TRightSet(R1::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TRights> VmIo for Vmo<TRightSet<R>> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
|
||||
self.check_rights(Rights::READ)?;
|
||||
self.0.read(offset, writer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
|
||||
self.check_rights(Rights::WRITE)?;
|
||||
self.0.write(offset, reader)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TRights> VmIoFill for Vmo<TRightSet<R>> {
|
||||
fn fill_zeros(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
) -> core::result::Result<(), (ostd::Error, usize)> {
|
||||
// TODO: Support efficient `fill_zeros()`.
|
||||
for i in 0..len {
|
||||
match self.write_slice(offset + i, &[0u8]) {
|
||||
Ok(()) => continue,
|
||||
Err(err) => return Err((err, i)),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TRights> VmoRightsOp for Vmo<TRightSet<R>> {
|
||||
fn rights(&self) -> Rights {
|
||||
Rights::from_bits(R::BITS).unwrap()
|
||||
}
|
||||
|
||||
/// Converts to a dynamic capability.
|
||||
fn to_dyn(self) -> Vmo<Rights> {
|
||||
let rights = self.rights();
|
||||
Vmo(self.0, rights)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue