WIP: Support userspace-backed borrowing mmaps.
This commit is contained in:
@@ -64,7 +64,7 @@ impl Status {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum HardBlockedReason {
|
||||
AwaitingMmap { ctxt: Arc<FmapCtxt>, finished: Option<Frame> },
|
||||
AwaitingMmap { ctxt: Arc<FmapCtxt> },
|
||||
// TODO: PageFaultOom?
|
||||
// TODO: NotYetStarted/ManuallyBlocked (when new contexts are created)
|
||||
// TODO: ptrace_stop?
|
||||
@@ -294,6 +294,7 @@ pub struct Context {
|
||||
/// set since there is no interrupt stack (unless the kernel stack is copied, but that is in my
|
||||
/// opinion hackier and less efficient than this (and UB to do in Rust)).
|
||||
pub clone_entry: Option<[usize; 2]>,
|
||||
pub fmap_ret: Option<Frame>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -336,6 +337,7 @@ impl Context {
|
||||
ptrace_stop: false,
|
||||
sigstack: None,
|
||||
clone_entry: None,
|
||||
fmap_ret: None,
|
||||
};
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
+21
-6
@@ -115,7 +115,8 @@ impl AddrSpace {
|
||||
false,
|
||||
fmap.as_ref().map(Arc::clone),
|
||||
)?,
|
||||
Provider::FmapBorrowed { ref fmap } => Grant::borrow_fmap(PageSpan::new(grant_base, grant_info.page_count), grant_info.flags(), Arc::clone(fmap)),
|
||||
// TODO: "clone grant using fmap"
|
||||
Provider::FmapBorrowed { .. } => continue,
|
||||
};
|
||||
|
||||
new_guard.grants.insert(new_grant);
|
||||
@@ -660,7 +661,18 @@ impl Grant {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn borrow_fmap(span: PageSpan, flags: PageFlags<RmmA>, fmap: Arc<FmapCtxt>) -> Self {
|
||||
pub fn borrow_fmap(span: PageSpan, flags: PageFlags<RmmA>, fmap: Arc<FmapCtxt>, src: Option<BorrowedFmapSource<'_>>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Self {
|
||||
if let Some(mut src) = src {
|
||||
for dst_page in span.pages() {
|
||||
let src_page = src.src_page.next_by(dst_page.offset_from(span.base));
|
||||
|
||||
let (frame, _) = src.src_mapper.translate(src_page.start_address()).unwrap();
|
||||
unsafe {
|
||||
flusher.consume(mapper.map_phys(dst_page.start_address(), frame, flags).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
base: span.base,
|
||||
info: GrantInfo {
|
||||
@@ -1250,13 +1262,11 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re
|
||||
user_inner.request_fmap(scheme_number, offset, 1, flags).unwrap();
|
||||
|
||||
let context_lock = super::current().map_err(|_| PfError::NonfatalInternalError)?;
|
||||
context_lock.write().hard_block(HardBlockedReason::AwaitingMmap { ctxt, finished: None });
|
||||
context_lock.write().hard_block(HardBlockedReason::AwaitingMmap { ctxt });
|
||||
|
||||
unsafe { super::switch(); }
|
||||
|
||||
let super::Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { finished: Some(frame), .. } } = core::mem::replace(&mut context_lock.write().status, super::Status::Runnable) else {
|
||||
return Err(PfError::NonfatalInternalError);
|
||||
};
|
||||
let frame = context_lock.write().fmap_ret.take().ok_or(PfError::NonfatalInternalError)?;
|
||||
|
||||
addr_space_guard = addr_space_lock.write();
|
||||
addr_space = &mut *addr_space_guard;
|
||||
@@ -1286,3 +1296,8 @@ pub enum MmapMode {
|
||||
Cow,
|
||||
Shared,
|
||||
}
|
||||
|
||||
pub struct BorrowedFmapSource<'a> {
|
||||
pub src_page: Page,
|
||||
pub src_mapper: &'a PageMapper,
|
||||
}
|
||||
|
||||
+28
-10
@@ -1,6 +1,7 @@
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::BTreeMap;
|
||||
use rmm::PageFlushAll;
|
||||
use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -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, FmapCtxt};
|
||||
use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, FmapCtxt, BorrowedFmapSource};
|
||||
use crate::event;
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{PAGE_SIZE, Page, VirtualAddress};
|
||||
@@ -39,6 +40,7 @@ pub struct UserInner {
|
||||
fmap: Mutex<BTreeMap<u64, Weak<RwLock<Context>>>>,
|
||||
unmounting: AtomicBool,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum Response {
|
||||
Regular(usize),
|
||||
Fd(Arc<RwLock<FileDescription>>),
|
||||
@@ -346,6 +348,7 @@ impl UserInner {
|
||||
Ok(packets_read * mem::size_of::<Packet>())
|
||||
}
|
||||
pub fn request_fmap(&self, id: usize, offset: u64, required_page_count: usize, flags: MapFlags) -> Result<()> {
|
||||
log::info!("REQUEST FMAP");
|
||||
self.todo.send(Packet {
|
||||
id: self.next_id(),
|
||||
pid: context::context_id().into(),
|
||||
@@ -383,26 +386,27 @@ impl UserInner {
|
||||
let offset = u64::from(packet.uid) | (u64::from(packet.gid) << 32);
|
||||
|
||||
if offset % PAGE_SIZE as u64 != 0 {
|
||||
return dbg!(Err(Error::new(EINVAL)));
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let base_addr = VirtualAddress::new(packet.c);
|
||||
if base_addr.data() % PAGE_SIZE != 0 {
|
||||
return dbg!(Err(Error::new(EINVAL)));
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let page_count = packet.d;
|
||||
|
||||
if page_count != 1 { return dbg!(Err(Error::new(EINVAL))); }
|
||||
if page_count != 1 { return Err(Error::new(EINVAL)); }
|
||||
let context = self.fmap.lock().remove(&packet.id).ok_or(Error::new(EINVAL))?.upgrade().ok_or(Error::new(ESRCH))?;
|
||||
|
||||
let (frame, _) = AddrSpace::current()?.read().table.utable.translate(base_addr).ok_or(Error::new(EFAULT))?;
|
||||
|
||||
let mut context = context.write();
|
||||
match context.status {
|
||||
Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { ref mut finished, .. } } => *finished = Some(Frame::containing_address(frame)),
|
||||
Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { .. } } => context.status = Status::Runnable,
|
||||
_ => (),
|
||||
}
|
||||
context.fmap_ret = Some(Frame::containing_address(frame));
|
||||
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
@@ -433,7 +437,7 @@ impl UserInner {
|
||||
}
|
||||
|
||||
if map.address % PAGE_SIZE != 0 {
|
||||
return Err(Error::new(EINVAL))
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
let dst_base = (map.address != 0).then_some(Page::containing_address(VirtualAddress::new(map.address)));
|
||||
|
||||
@@ -447,6 +451,11 @@ impl UserInner {
|
||||
MmapMode::Cow
|
||||
};
|
||||
|
||||
let src_address_space = Arc::clone(
|
||||
self.context.upgrade().ok_or(Error::new(ENODEV))?
|
||||
.read().addr_space()?
|
||||
);
|
||||
|
||||
let (pid, desc) = {
|
||||
let context_lock = context::current()?;
|
||||
let context = context_lock.read();
|
||||
@@ -481,8 +490,9 @@ impl UserInner {
|
||||
gid: (map.offset >> 32) as u32,
|
||||
})?;
|
||||
|
||||
let _ = match response {
|
||||
Response::Regular(code) => Error::demux(code)?,
|
||||
let base_page_opt = match response {
|
||||
Response::Regular(code) => (!map.flags.contains(MapFlags::MAP_LAZY))
|
||||
.then_some(Error::demux(code)?),
|
||||
Response::Fd(_) => {
|
||||
log::debug!("Scheme incorrectly returned an fd for fmap.");
|
||||
|
||||
@@ -499,9 +509,17 @@ impl UserInner {
|
||||
base_offset: map.offset,
|
||||
},
|
||||
});
|
||||
let src_guard = src_address_space.read();
|
||||
let src = match base_page_opt {
|
||||
Some(base_addr) => Some(BorrowedFmapSource {
|
||||
src_page: Page::containing_address(VirtualAddress::new(base_addr)),
|
||||
src_mapper: &src_guard.table.utable,
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0");
|
||||
dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, _mapper, _flusher| {
|
||||
Ok(Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), ctxt))
|
||||
dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, mapper, flusher| {
|
||||
Ok(Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), ctxt, src, mapper, flusher))
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
Submodule syscall updated: 6024e1e1fa...d587771fc3
Reference in New Issue
Block a user