Implement MAP_FIXED without MAP_FIXED_NOREPLACE.

This commit is contained in:
4lDO2
2023-07-03 18:33:16 +02:00
parent f0341280f7
commit 70b4d99c96
6 changed files with 76 additions and 54 deletions
+50 -39
View File
@@ -203,7 +203,8 @@ impl AddrSpace {
}
Ok(())
}
pub fn munmap(mut self: RwLockWriteGuard<'_, Self>, mut requested_span: PageSpan, unpin: bool) -> Result<()> {
#[must_use = "needs to notify files"]
pub fn munmap(&mut self, mut requested_span: PageSpan, unpin: bool) -> Result<Vec<UnmapResult>> {
let mut notify_files = Vec::new();
let mut flusher = PageFlushAll::new();
@@ -249,17 +250,44 @@ impl AddrSpace {
notify_files.push(unmap_result);
}
}
drop(self);
for unmap_result in notify_files {
let _ = unmap_result.unmap();
}
Ok(())
Ok(notify_files)
}
pub fn mmap(&mut self, page: Option<Page>, page_count: NonZeroUsize, flags: MapFlags, map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>) -> Result<Page> {
// Finally, the end of all "T0DO: Abstract with other grant creation"!
let selected_span = self.grants.find_free_at(self.mmap_min, page, page_count.get(), flags)?;
pub fn mmap_anywhere(&mut self, page_count: NonZeroUsize, flags: MapFlags, map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>) -> Result<Page> {
self.mmap(None, page_count, flags, &mut Vec::new(), map)
}
pub fn mmap(
&mut self,
requested_base_opt: Option<Page>,
page_count: NonZeroUsize,
flags: MapFlags,
notify_files_out: &mut Vec<UnmapResult>,
map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>,
) -> Result<Page> {
let selected_span = match requested_base_opt {
Some(requested_base) => {
let requested_span = PageSpan::new(requested_base, page_count.get());
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) && self.grants.conflicts(requested_span).next().is_some() {
return Err(Error::new(EEXIST));
}
// TODO: Rename MAP_FIXED+MAP_FIXED_NOREPLACE to MAP_FIXED and
// MAP_FIXED_REPLACE/MAP_REPLACE?
let map_fixed_replace = flags.contains(MapFlags::MAP_FIXED);
if map_fixed_replace {
let unpin = false;
let mut notify_files = self.munmap(requested_span, unpin)?;
notify_files_out.append(&mut notify_files);
requested_span
} else {
self.grants.find_free_near(self.mmap_min, page_count.get(), Some(requested_base)).ok_or(Error::new(ENOMEM))?
}
}
None => self.grants.find_free(self.mmap_min, page_count.get()).ok_or(Error::new(ENOMEM))?,
};
// TODO: Threads share address spaces, so not only the inactive flusher should be sending
// out IPIs. IPIs will only be sent when downgrading mappings (i.e. when a stale TLB entry
@@ -279,7 +307,7 @@ impl AddrSpace {
Ok(selected_span.base)
}
pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option<Page>, new_flags: MapFlags) -> Result<Page> {
pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option<Page>, new_flags: MapFlags, notify_files: &mut Vec<UnmapResult>) -> Result<Page> {
let nz_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
let grant_base = {
@@ -305,7 +333,7 @@ impl AddrSpace {
let src_flusher = PageFlushAll::new();
dst.mmap(requested_dst_base, nz_count, new_flags, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, dst_mapper, src_flusher, dst_flusher))
dst.mmap(requested_dst_base, nz_count, new_flags, notify_files, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, dst_mapper, src_flusher, dst_flusher))
}
}
@@ -447,7 +475,8 @@ impl UserGrants {
}
/// Return a free region with the specified size
// TODO: Alignment (x86_64: 4 KiB, 2 MiB, or 1 GiB).
pub fn find_free(&self, min: usize, page_count: usize) -> Option<PageSpan> {
// TODO: Support finding grant close to a requested address?
pub fn find_free_near(&self, min: usize, page_count: usize, _near: Option<Page>) -> Option<PageSpan> {
// Get first available hole, but do reserve the page starting from zero as most compiled
// languages cannot handle null pointers safely even if they point to valid memory. If an
// application absolutely needs to map the 0th page, they will have to do so explicitly via
@@ -468,32 +497,8 @@ impl UserGrants {
// Create new region
Some(PageSpan::new(Page::containing_address(VirtualAddress::new(cmp::max(hole_start.data(), min))), page_count))
}
/// Return a free region, respecting the user's hinted address and flags. Address may be null.
pub fn find_free_at(&mut self, min: usize, base: Option<Page>, page_count: usize, flags: MapFlags) -> Result<PageSpan> {
let Some(requested_base) = base else {
// Free hands!
return self.find_free(min, page_count).ok_or(Error::new(ENOMEM));
};
// The user wished to have this region...
let requested_span = PageSpan::new(requested_base, page_count);
if let Some(_grant) = self.conflicts(requested_span).next() {
// ... but it already exists
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
return Err(Error::new(EEXIST));
}
if flags.contains(MapFlags::MAP_FIXED) {
// TODO: find_free_at -> Result<(PageSpan, needs_to_unmap: PageSpan)>
return Err(Error::new(EOPNOTSUPP));
} else {
// TODO: Find grant close to requested address?
return self.find_free(min, page_count).ok_or(Error::new(ENOMEM));
}
}
Ok(requested_span)
pub fn find_free(&self, min: usize, page_count: usize) -> Option<PageSpan> {
self.find_free_near(min, page_count, None)
}
fn reserve(&mut self, base: Page, page_count: usize) {
let start_address = base.start_address();
@@ -1484,3 +1489,9 @@ pub struct BorrowedFmapSource<'a> {
pub addr_space_lock: &'a RwLock<AddrSpace>,
pub addr_space_guard: RwLockWriteGuard<'a, AddrSpace>,
}
pub fn handle_notify_files(notify_files: Vec<UnmapResult>) {
for file in notify_files {
let _ = file.unmap();
}
}
+8 -3
View File
@@ -2,11 +2,12 @@ use core::num::NonZeroUsize;
use alloc::sync::Arc;
use rmm::PhysicalAddress;
use alloc::vec::Vec;
use spin::RwLock;
use syscall::MapFlags;
use crate::context::memory::{AddrSpace, Grant, PageSpan};
use crate::memory::{free_frames, used_frames, PAGE_SIZE, Frame};
use crate::context::memory::{AddrSpace, Grant, PageSpan, handle_notify_files};
use crate::paging::VirtualAddress;
use crate::paging::entry::EntryFlags;
@@ -59,12 +60,16 @@ impl MemoryScheme {
let span = PageSpan::validate_nonempty(VirtualAddress::new(map.address), map.size).ok_or(Error::new(EINVAL))?;
let page_count = NonZeroUsize::new(span.count).ok_or(Error::new(EINVAL))?;
let mut notify_files = Vec::new();
let page = addr_space
.write()
.mmap((map.address != 0).then_some(span.base), page_count, map.flags, |dst_page, flags, mapper, flusher| {
.mmap((map.address != 0).then_some(span.base), page_count, map.flags, &mut notify_files, |dst_page, flags, mapper, flusher| {
Ok(Grant::zeroed(PageSpan::new(dst_page, page_count.get()), flags, mapper, flusher)?)
})?;
handle_notify_files(notify_files);
Ok(page.start_address().data())
}
pub fn physmap(physical_address: usize, size: usize, flags: MapFlags, memory_type: MemoryType) -> Result<usize> {
@@ -82,7 +87,7 @@ impl MemoryScheme {
}
let page_count = NonZeroUsize::new(size.div_ceil(PAGE_SIZE)).ok_or(Error::new(EINVAL))?;
AddrSpace::current()?.write().mmap(None, page_count, flags, |dst_page, mut page_flags, dst_mapper, dst_flusher| {
AddrSpace::current()?.write().mmap_anywhere(page_count, flags, |dst_page, mut page_flags, dst_mapper, dst_flusher| {
match memory_type {
// Default
MemoryType::Writeback => (),
+7 -3
View File
@@ -1,6 +1,6 @@
use crate::{
arch::paging::{mapper::InactiveFlusher, Page, RmmA, RmmArch, VirtualAddress},
context::{self, Context, ContextId, Status, file::{FileDescription, FileDescriptor}, memory::{AddrSpace, Grant, new_addrspace, map_flags, PageSpan}, BorrowedHtBuf},
context::{self, Context, ContextId, Status, file::{FileDescription, FileDescriptor}, memory::{AddrSpace, Grant, new_addrspace, map_flags, PageSpan, handle_notify_files}, BorrowedHtBuf},
memory::PAGE_SIZE,
ptrace,
scheme::{self, FileHandle, KernelScheme, SchemeId},
@@ -690,13 +690,17 @@ impl KernelScheme for ProcScheme {
let src_page_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
let mut notify_files = Vec::new();
// TODO: Validate flags
let result_base = if consume {
AddrSpace::r#move(&mut *dst_addr_space, &mut *src_addr_space, src_span, requested_dst_base, map.flags)?
AddrSpace::r#move(&mut *dst_addr_space, &mut *src_addr_space, src_span, requested_dst_base, map.flags, &mut notify_files)?
} else {
dst_addr_space.mmap(requested_dst_base, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), &*src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))?
dst_addr_space.mmap(requested_dst_base, src_page_count, map.flags, &mut notify_files, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), &*src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))?
};
handle_notify_files(notify_files);
Ok(result_base.start_address().data())
}
_ => Err(Error::new(EBADF)),
+8 -7
View File
@@ -1,7 +1,8 @@
use alloc::sync::{Arc, Weak};
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP};
use alloc::vec::Vec;
use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP, MAP_FIXED_NOREPLACE};
use core::num::NonZeroUsize;
use core::sync::atomic::{AtomicBool, Ordering};
use core::{mem, usize};
@@ -11,7 +12,7 @@ use spin::{Mutex, RwLock};
use crate::context::context::HardBlockedReason;
use crate::context::{self, Context, BorrowedHtBuf, Status};
use crate::context::file::FileDescription;
use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, BorrowedFmapSource};
use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, BorrowedFmapSource, handle_notify_files};
use crate::event;
use crate::memory::Frame;
use crate::paging::{PAGE_SIZE, Page, VirtualAddress};
@@ -146,7 +147,7 @@ impl UserInner {
let src_page = Page::containing_address(VirtualAddress::new(tail.buf_mut().as_ptr() as usize));
let is_pinned = true;
let dst_page = dst_addr_space.write().mmap(None, ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::physmap(tail_frame, PageSpan::new(dst_page, 1), flags, mapper, flusher, is_pinned)?))?;
let dst_page = dst_addr_space.write().mmap_anywhere(ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::physmap(tail_frame, PageSpan::new(dst_page, 1), flags, mapper, flusher, is_pinned)?))?;
Ok(CaptureGuard {
destroyed: false,
@@ -240,7 +241,7 @@ impl UserInner {
}
}
dst_space.mmap(Some(free_span.base), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
dst_space.mmap(Some(free_span.base), ONE, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
let is_pinned = true;
Ok(Grant::physmap(frame, PageSpan::new(dst_page, 1), page_flags, mapper, flusher, is_pinned)?)
})?;
@@ -265,7 +266,7 @@ impl UserInner {
let (_middle_part_of_buf, tail_part_of_buf) = middle_tail_part_of_buf.split_at(middle_page_count * PAGE_SIZE).expect("split must succeed");
if let Some(middle_page_count) = NonZeroUsize::new(middle_page_count) {
dst_space.mmap(Some(first_middle_dst_page), middle_page_count, map_flags, move |dst_page, page_flags, mapper, flusher| {
dst_space.mmap(Some(first_middle_dst_page), middle_page_count, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
let eager = true;
// It doesn't make sense to allow a context, that has borrowed non-RAM physical
@@ -304,7 +305,7 @@ impl UserInner {
}
}
dst_space.mmap(Some(tail_dst_page), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
dst_space.mmap(Some(tail_dst_page), ONE, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
let is_pinned = true;
Ok(Grant::physmap(frame, PageSpan::new(dst_page, 1), page_flags, mapper, flusher, is_pinned)?)
})?;
@@ -545,7 +546,7 @@ impl UserInner {
};
let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0");
let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, mapper, flusher| {
let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), |dst_base, flags, mapper, flusher| {
Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), file_ref, src, mapper, flusher)
})?;
+1
View File
@@ -9,6 +9,7 @@ use crate::syscall::flag::{MapFlags, PhysallocFlags, PartialAllocStrategy, Physm
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use alloc::sync::Arc;
use alloc::vec::Vec;
use super::usercopy::UserSliceRw;
+2 -2
View File
@@ -174,13 +174,13 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
}
}
let mut debug = false;
let mut debug = true;
debug = debug && {
let contexts = crate::context::contexts();
if let Some(context_lock) = contexts.current() {
let context = context_lock.read();
if context.name.contains("orb") {
if context.name.contains("dash") {
if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
false
} else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {