mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 12:06:43 +00:00
Rename fork_vmar to fork_from
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d9fcb486c0
commit
baeaa9b4d3
@ -340,7 +340,7 @@ fn clone_vm(parent_process_vm: &ProcessVm, clone_flags: CloneFlags) -> Result<Pr
|
||||
if clone_flags.contains(CloneFlags::CLONE_VM) {
|
||||
Ok(parent_process_vm.clone())
|
||||
} else {
|
||||
let root_vmar = parent_process_vm.root_vmar().fork_vmar()?;
|
||||
let root_vmar = Vmar::<Full>::fork_from(parent_process_vm.root_vmar())?;
|
||||
let user_heap = parent_process_vm.user_heap().clone();
|
||||
Ok(ProcessVm::new(user_heap, root_vmar))
|
||||
}
|
||||
|
@ -134,9 +134,7 @@ impl<'a> ProcessBuilder<'a> {
|
||||
sig_dispositions,
|
||||
} = self;
|
||||
|
||||
let process_vm = process_vm
|
||||
.or_else(|| Some(ProcessVm::alloc().unwrap()))
|
||||
.unwrap();
|
||||
let process_vm = process_vm.or_else(|| Some(ProcessVm::alloc())).unwrap();
|
||||
|
||||
let process_group_ref = process_group
|
||||
.as_ref()
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
pub mod user_heap;
|
||||
|
||||
use crate::prelude::*;
|
||||
use jinux_rights::Full;
|
||||
use user_heap::UserHeap;
|
||||
|
||||
@ -55,14 +54,14 @@ impl Clone for ProcessVm {
|
||||
}
|
||||
|
||||
impl ProcessVm {
|
||||
pub fn alloc() -> Result<Self> {
|
||||
let root_vmar = Vmar::<Full>::new_root()?;
|
||||
pub fn alloc() -> Self {
|
||||
let root_vmar = Vmar::<Full>::new_root();
|
||||
let user_heap = UserHeap::new();
|
||||
user_heap.init(&root_vmar);
|
||||
Ok(ProcessVm {
|
||||
ProcessVm {
|
||||
user_heap,
|
||||
root_vmar,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(user_heap: UserHeap, root_vmar: Vmar<Full>) -> Self {
|
||||
|
@ -44,8 +44,7 @@ impl KernelThreadExt for Thread {
|
||||
};
|
||||
let tid = allocate_tid();
|
||||
let thread = Arc::new_cyclic(|thread_ref| {
|
||||
let weal_thread = thread_ref.clone();
|
||||
let task = Task::new(thread_fn, weal_thread, None).unwrap();
|
||||
let task = Task::new(thread_fn, thread_ref.clone(), None).unwrap();
|
||||
let status = ThreadStatus::Init;
|
||||
let kernel_thread = KernelThread;
|
||||
Thread::new(tid, task, kernel_thread, status)
|
||||
|
@ -12,11 +12,10 @@ use super::{
|
||||
|
||||
impl Vmar<Rights> {
|
||||
/// Creates a root VMAR.
|
||||
pub fn new_root() -> Result<Self> {
|
||||
let inner = Arc::new(Vmar_::new_root()?);
|
||||
pub fn new_root() -> Self {
|
||||
let inner = Vmar_::new_root();
|
||||
let rights = Rights::all();
|
||||
let new_self = Self(inner, rights);
|
||||
Ok(new_self)
|
||||
Self(inner, rights)
|
||||
}
|
||||
|
||||
/// Maps the given VMO into the VMAR through a set of VMAR mapping options.
|
||||
@ -143,10 +142,16 @@ impl Vmar<Rights> {
|
||||
Ok(Vmar(self.0.clone(), self.1))
|
||||
}
|
||||
|
||||
/// Given a map size, returns the possible map address without doing actual allocation.
|
||||
pub fn hint_map_addr(&self, map_size: usize) -> Result<Vaddr> {
|
||||
self.check_rights(Rights::READ)?;
|
||||
self.0.hint_map_addr(map_size)
|
||||
/// Creates a new root VMAR whose content is inherited from another
|
||||
/// using copy-on-write (COW) technique.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Read right.
|
||||
pub fn fork_from(vmar: &Vmar) -> Result<Self> {
|
||||
vmar.check_rights(Rights::READ)?;
|
||||
let vmar_ = vmar.0.new_cow_root()?;
|
||||
Ok(Vmar(vmar_, Rights::all()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use alloc::sync::Weak;
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
use jinux_frame::vm::VmSpace;
|
||||
use jinux_rights::{Dup, Exec, Full, Read, Rights, Signal, TRightSet, TRights, Write};
|
||||
use jinux_rights::Rights;
|
||||
|
||||
use self::vm_mapping::VmMapping;
|
||||
|
||||
@ -112,14 +112,47 @@ struct VmarInner {
|
||||
free_regions: BTreeMap<Vaddr, FreeRegion>,
|
||||
}
|
||||
|
||||
impl VmarInner {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
is_destroyed: false,
|
||||
child_vmar_s: BTreeMap::new(),
|
||||
vm_mappings: BTreeMap::new(),
|
||||
free_regions: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: How to set the correct root vmar range?
|
||||
// We should not include addr 0 here(is this right?), since the 0 addr means the null pointer.
|
||||
// We should include addr 0x0040_0000, since non-pie executables typically are put on 0x0040_0000.
|
||||
pub const ROOT_VMAR_LOWEST_ADDR: Vaddr = 0x0010_0000;
|
||||
pub const ROOT_VMAR_HIGHEST_ADDR: Vaddr = 0x1000_0000_0000;
|
||||
const ROOT_VMAR_LOWEST_ADDR: Vaddr = 0x0010_0000;
|
||||
const ROOT_VMAR_HIGHEST_ADDR: Vaddr = 0x1000_0000_0000;
|
||||
|
||||
impl Vmar_ {
|
||||
pub fn new_root() -> Result<Self> {
|
||||
fn new(
|
||||
inner: VmarInner,
|
||||
vm_space: VmSpace,
|
||||
base: usize,
|
||||
size: usize,
|
||||
parent: Option<&Arc<Vmar_>>,
|
||||
) -> Arc<Self> {
|
||||
let parent = if let Some(parent) = parent {
|
||||
Arc::downgrade(parent)
|
||||
} else {
|
||||
Weak::new()
|
||||
};
|
||||
|
||||
Arc::new(Vmar_ {
|
||||
inner: Mutex::new(inner),
|
||||
base,
|
||||
size,
|
||||
vm_space,
|
||||
parent,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_root() -> Arc<Self> {
|
||||
let mut free_regions = BTreeMap::new();
|
||||
let root_region = FreeRegion::new(ROOT_VMAR_LOWEST_ADDR..ROOT_VMAR_HIGHEST_ADDR);
|
||||
free_regions.insert(root_region.start(), root_region);
|
||||
@ -129,14 +162,7 @@ impl Vmar_ {
|
||||
vm_mappings: BTreeMap::new(),
|
||||
free_regions,
|
||||
};
|
||||
let vmar_ = Vmar_ {
|
||||
inner: Mutex::new(vmar_inner),
|
||||
vm_space: VmSpace::new(),
|
||||
base: 0,
|
||||
size: ROOT_VMAR_HIGHEST_ADDR,
|
||||
parent: Weak::new(),
|
||||
};
|
||||
Ok(vmar_)
|
||||
Vmar_::new(vmar_inner, VmSpace::new(), 0, ROOT_VMAR_HIGHEST_ADDR, None)
|
||||
}
|
||||
|
||||
fn is_root_vmar(&self) -> bool {
|
||||
@ -445,13 +471,13 @@ impl Vmar_ {
|
||||
vm_mappings: BTreeMap::new(),
|
||||
free_regions: child_regions,
|
||||
};
|
||||
let child_vmar_ = Arc::new(Vmar_ {
|
||||
inner: Mutex::new(child_vmar_inner),
|
||||
base: child_vmar_offset,
|
||||
size: child_vmar_size,
|
||||
vm_space: self.vm_space.clone(),
|
||||
parent: Arc::downgrade(self),
|
||||
});
|
||||
let child_vmar_ = Vmar_::new(
|
||||
child_vmar_inner,
|
||||
self.vm_space.clone(),
|
||||
child_vmar_offset,
|
||||
child_vmar_size,
|
||||
Some(self),
|
||||
);
|
||||
self.inner
|
||||
.lock()
|
||||
.child_vmar_s
|
||||
@ -591,16 +617,6 @@ impl Vmar_ {
|
||||
}
|
||||
}
|
||||
|
||||
fn hint_map_addr(&self, size: usize) -> Result<Vaddr> {
|
||||
let inner = self.inner.lock();
|
||||
for (free_region_base, free_region) in &inner.free_regions {
|
||||
if free_region.size() >= size {
|
||||
return Ok(*free_region_base);
|
||||
}
|
||||
}
|
||||
return_errno_with_message!(Errno::ENOMEM, "cannot find a suitale free region");
|
||||
}
|
||||
|
||||
fn trim_existing_mappings(&self, trim_range: Range<usize>) -> Result<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
let mut mappings_to_remove = BTreeSet::new();
|
||||
@ -622,35 +638,28 @@ impl Vmar_ {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// fork vmar for child process
|
||||
pub fn fork_vmar_(&self, parent: Weak<Vmar_>) -> Result<Arc<Self>> {
|
||||
// create an empty vmar at first
|
||||
let is_destroyed = false;
|
||||
let child_vmar_s = BTreeMap::new();
|
||||
let mapped_vmos = BTreeMap::new();
|
||||
let free_regions = BTreeMap::new();
|
||||
let vmar_inner = VmarInner {
|
||||
is_destroyed,
|
||||
child_vmar_s,
|
||||
vm_mappings: mapped_vmos,
|
||||
free_regions,
|
||||
};
|
||||
// If this is a root vmar, we create a new vmspace
|
||||
// Otherwise, we clone the vm space from parent.
|
||||
let vm_space = if let Some(parent) = parent.upgrade() {
|
||||
parent.vm_space().clone()
|
||||
} else {
|
||||
VmSpace::new()
|
||||
};
|
||||
let vmar_ = Vmar_ {
|
||||
inner: Mutex::new(vmar_inner),
|
||||
base: self.base,
|
||||
size: self.size,
|
||||
vm_space,
|
||||
parent,
|
||||
pub(super) fn new_cow_root(self: &Arc<Self>) -> Result<Arc<Self>> {
|
||||
if self.parent.upgrade().is_some() {
|
||||
return_errno_with_message!(Errno::EINVAL, "can only dup cow vmar for root vmar");
|
||||
}
|
||||
|
||||
self.new_cow(None)
|
||||
}
|
||||
|
||||
/// Create a new vmar by creating cow child for all mapped vmos
|
||||
fn new_cow(&self, parent: Option<&Arc<Vmar_>>) -> Result<Arc<Self>> {
|
||||
let new_vmar_ = {
|
||||
let vmar_inner = VmarInner::new();
|
||||
// If this is a root vmar, we create a new vmspace,
|
||||
// Otherwise, we clone the vm space from parent.
|
||||
let vm_space = if let Some(parent) = parent {
|
||||
parent.vm_space().clone()
|
||||
} else {
|
||||
VmSpace::new()
|
||||
};
|
||||
Vmar_::new(vmar_inner, vm_space, self.base, self.size, parent)
|
||||
};
|
||||
|
||||
let new_vmar_ = Arc::new(vmar_);
|
||||
let inner = self.inner.lock();
|
||||
// clone free regions
|
||||
for (free_region_base, free_region) in &inner.free_regions {
|
||||
@ -663,30 +672,28 @@ impl Vmar_ {
|
||||
|
||||
// clone child vmars
|
||||
for (child_vmar_base, child_vmar_) in &inner.child_vmar_s {
|
||||
let parent_of_forked_child = Arc::downgrade(&new_vmar_);
|
||||
let forked_child_vmar = child_vmar_.fork_vmar_(parent_of_forked_child)?;
|
||||
let new_child_vmar = child_vmar_.new_cow(Some(&new_vmar_))?;
|
||||
new_vmar_
|
||||
.inner
|
||||
.lock()
|
||||
.child_vmar_s
|
||||
.insert(*child_vmar_base, forked_child_vmar);
|
||||
.insert(*child_vmar_base, new_child_vmar);
|
||||
}
|
||||
|
||||
// clone vm mappings
|
||||
for (vm_mapping_base, vm_mapping) in &inner.vm_mappings {
|
||||
let parent_of_forked_mapping = Arc::downgrade(&new_vmar_);
|
||||
let forked_mapping = Arc::new(vm_mapping.fork_mapping(parent_of_forked_mapping)?);
|
||||
let new_mapping = Arc::new(vm_mapping.new_cow(&new_vmar_)?);
|
||||
new_vmar_
|
||||
.inner
|
||||
.lock()
|
||||
.vm_mappings
|
||||
.insert(*vm_mapping_base, forked_mapping);
|
||||
.insert(*vm_mapping_base, new_mapping);
|
||||
}
|
||||
Ok(new_vmar_)
|
||||
}
|
||||
|
||||
/// get mapped vmo at given offset
|
||||
pub fn get_vm_mapping(&self, offset: Vaddr) -> Result<Arc<VmMapping>> {
|
||||
fn get_vm_mapping(&self, offset: Vaddr) -> Result<Arc<VmMapping>> {
|
||||
for (vm_mapping_base, vm_mapping) in &self.inner.lock().vm_mappings {
|
||||
if *vm_mapping_base <= offset && offset < *vm_mapping_base + vm_mapping.map_size() {
|
||||
return Ok(vm_mapping.clone());
|
||||
@ -709,17 +716,6 @@ impl<R> Vmar<R> {
|
||||
self.0.size
|
||||
}
|
||||
|
||||
/// Fork a vmar for child process
|
||||
pub fn fork_vmar(&self) -> Result<Vmar<Full>> {
|
||||
let rights = Rights::all();
|
||||
self.check_rights(rights)?;
|
||||
let vmar_ = self.0.fork_vmar_(Weak::new())?;
|
||||
Ok(Vmar(
|
||||
vmar_,
|
||||
TRightSet(<TRights![Dup, Read, Write, Exec, Signal]>::new()),
|
||||
))
|
||||
}
|
||||
|
||||
/// get a mapped vmo
|
||||
pub fn get_vm_mapping(&self, offset: Vaddr) -> Result<Arc<VmMapping>> {
|
||||
let rights = Rights::all();
|
||||
|
@ -144,13 +144,13 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn root_vmar() {
|
||||
let vmar = Vmar::<Full>::new_root().unwrap();
|
||||
let vmar = Vmar::<Full>::new_root();
|
||||
assert!(vmar.size() == ROOT_VMAR_HIGHEST_ADDR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn child_vmar() {
|
||||
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||
let root_vmar = Vmar::<Full>::new_root();
|
||||
let root_vmar_dup = root_vmar.dup().unwrap();
|
||||
let child_vmar = VmarChildOptions::new(root_vmar_dup, 10 * PAGE_SIZE)
|
||||
.alloc()
|
||||
@ -169,7 +169,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn map_vmo() {
|
||||
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||
let root_vmar = Vmar::<Full>::new_root();
|
||||
let vmo = VmoOptions::<Full>::new(PAGE_SIZE).alloc().unwrap().to_dyn();
|
||||
let perms = VmPerms::READ | VmPerms::WRITE;
|
||||
let map_offset = 0x1000_0000;
|
||||
@ -196,7 +196,7 @@ mod test {
|
||||
#[test]
|
||||
fn handle_page_fault() {
|
||||
const OFFSET: usize = 0x1000_0000;
|
||||
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||
let root_vmar = Vmar::<Full>::new_root();
|
||||
// the page is not mapped by a vmo
|
||||
assert!(root_vmar.handle_page_fault(OFFSET, true, true).is_err());
|
||||
// the page is mapped READ
|
||||
|
@ -2,7 +2,7 @@ use core::ops::Range;
|
||||
|
||||
use crate::prelude::*;
|
||||
use jinux_frame::vm::VmIo;
|
||||
use jinux_rights::{Dup, Read, Rights, TRightSet, TRights};
|
||||
use jinux_rights::{Dup, Rights, TRightSet, TRights};
|
||||
use jinux_rights_proc::require;
|
||||
|
||||
use crate::vm::{page_fault_handler::PageFaultHandler, vmo::Vmo};
|
||||
@ -17,11 +17,10 @@ impl<R: TRights> Vmar<TRightSet<R>> {
|
||||
/// # Access rights
|
||||
///
|
||||
/// A root VMAR is initially given full access rights.
|
||||
pub fn new_root() -> Result<Self> {
|
||||
let inner = Arc::new(Vmar_::new_root()?);
|
||||
pub fn new_root() -> Self {
|
||||
let inner = Vmar_::new_root();
|
||||
let rights = R::new();
|
||||
let new_self = Self(inner, TRightSet(rights));
|
||||
Ok(new_self)
|
||||
Self(inner, TRightSet(rights))
|
||||
}
|
||||
|
||||
/// Maps the given VMO into the VMAR through a set of VMAR mapping options.
|
||||
@ -150,10 +149,16 @@ impl<R: TRights> Vmar<TRightSet<R>> {
|
||||
Ok(Vmar(self.0.clone(), self.1))
|
||||
}
|
||||
|
||||
/// Given a map size, returns the possible map address without doing actual allocation.
|
||||
#[require(R > Read)]
|
||||
pub fn hint_map_addr(&self, map_size: usize) -> Result<Vaddr> {
|
||||
self.0.hint_map_addr(map_size)
|
||||
/// Creates a new root VMAR whose content is inherited from another
|
||||
/// using copy-on-write (COW) technique.
|
||||
///
|
||||
/// # Access rights
|
||||
///
|
||||
/// The method requires the Read right.
|
||||
pub fn fork_from<R1>(vmar: &Vmar<R1>) -> Result<Self> {
|
||||
vmar.check_rights(Rights::READ)?;
|
||||
let vmar_ = vmar.0.new_cow_root()?;
|
||||
Ok(Vmar(vmar_, TRightSet(R::new())))
|
||||
}
|
||||
|
||||
/// Strict the access rights.
|
||||
|
@ -101,6 +101,7 @@ impl VmMapping {
|
||||
mapped_pages: BTreeSet::new(),
|
||||
page_perms,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
inner: Mutex::new(vm_mapping_inner),
|
||||
parent: Arc::downgrade(&parent_vmar),
|
||||
@ -233,18 +234,30 @@ impl VmMapping {
|
||||
self.inner.lock().protect(vm_space, perms, range)
|
||||
}
|
||||
|
||||
pub(super) fn fork_mapping(&self, new_parent: Weak<Vmar_>) -> Result<VmMapping> {
|
||||
pub(super) fn new_cow(&self, new_parent: &Arc<Vmar_>) -> Result<VmMapping> {
|
||||
let VmMapping { inner, vmo, .. } = self;
|
||||
|
||||
let child_vmo = {
|
||||
let parent_vmo = vmo.dup().unwrap();
|
||||
let vmo_size = parent_vmo.size();
|
||||
VmoChildOptions::new_cow(parent_vmo, 0..vmo_size).alloc()?
|
||||
};
|
||||
|
||||
let inner = self.inner.lock().fork_mapping(child_vmo.size())?;
|
||||
let new_inner = {
|
||||
let inner = self.inner.lock();
|
||||
VmMappingInner {
|
||||
vmo_offset: inner.vmo_offset,
|
||||
map_size: inner.map_size,
|
||||
map_to_addr: inner.map_to_addr,
|
||||
is_destroyed: inner.is_destroyed,
|
||||
mapped_pages: BTreeSet::new(),
|
||||
page_perms: inner.page_perms.clone(),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(VmMapping {
|
||||
inner: Mutex::new(inner),
|
||||
parent: new_parent,
|
||||
inner: Mutex::new(new_inner),
|
||||
parent: Arc::downgrade(new_parent),
|
||||
vmo: child_vmo,
|
||||
})
|
||||
}
|
||||
@ -412,21 +425,6 @@ impl VmMappingInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fork_mapping(&self, vmo_size: usize) -> Result<VmMappingInner> {
|
||||
debug!(
|
||||
"fork vmo, parent size = 0x{:x}, map_to_addr = 0x{:x}",
|
||||
vmo_size, self.map_to_addr
|
||||
);
|
||||
Ok(VmMappingInner {
|
||||
is_destroyed: self.is_destroyed,
|
||||
mapped_pages: BTreeSet::new(),
|
||||
page_perms: self.page_perms.clone(),
|
||||
vmo_offset: self.vmo_offset,
|
||||
map_size: self.map_size,
|
||||
map_to_addr: self.map_to_addr,
|
||||
})
|
||||
}
|
||||
|
||||
/// trim the mapping from left to a new address.
|
||||
fn trim_left(&mut self, vm_space: &VmSpace, vaddr: Vaddr) -> Result<Vaddr> {
|
||||
trace!(
|
||||
|
Reference in New Issue
Block a user