From cbec83215a540e1e8159262c564894278da31e84 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 4 Jul 2023 18:29:52 +0200 Subject: [PATCH] Lazy-evaluate pages returned by fmap. --- src/context/memory.rs | 55 ++++++++++++++++++++++++++++--------------- src/scheme/proc.rs | 2 +- src/scheme/user.rs | 12 ++++------ 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/context/memory.rs b/src/context/memory.rs index 1ff6df9fc8..0bcfa86abd 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -706,22 +706,37 @@ impl Grant { pub fn borrow_fmap(span: PageSpan, new_flags: PageFlags, file_ref: GrantFileRef, src: Option>, mapper: &mut PageMapper, mut flusher: impl Flusher) -> Result { if let Some(mut src) = src { - // FIXME: Iterate over grants rather than pages, to allow for not-yet-lazily mapped - // pages. + let mut guard = src.addr_space_guard; for dst_page in span.pages() { let src_page = src.src_base.next_by(dst_page.offset_from(span.base)); let (frame, is_cow) = match src.mode { - MmapMode::Shared(src_mapper) => { + MmapMode::Shared => { // TODO: Error code for "scheme responded with unmapped page"? - let (frame, _) = src_mapper.translate(src_page.start_address()).ok_or(Error::new(EIO))?; + let frame = match guard.table.utable.translate(src_page.start_address()) { + Some((phys, _)) => Frame::containing_address(phys), + // TODO: ensure the correct context is hardblocked, if necessary + None => { + let (frame, _, new_guard) = correct_inner(src.addr_space_lock, guard, src_page, AccessMode::Read, 0).map_err(|_| Error::new(EIO))?; + guard = new_guard; + frame + } + }; - (Frame::containing_address(frame), false) + (frame, false) } - MmapMode::Cow(ref mut src_mapper) => unsafe { - let (_, frame, _) = src_mapper.remap_with(src_page.start_address(), |flags| flags.write(false)).ok_or(Error::new(EIO))?; + MmapMode::Cow => unsafe { + let frame = match guard.table.utable.remap_with(src_page.start_address(), |flags| flags.write(false)) { + Some((_, phys, _)) => Frame::containing_address(phys), + // TODO: ensure the correct context is hardblocked, if necessary + None => { + let (frame, _, new_guard) =correct_inner(src.addr_space_lock, guard, src_page, AccessMode::Read, 0).map_err(|_| Error::new(EIO))?; + guard = new_guard; + frame + } + }; - (Frame::containing_address(frame), true) + (frame, true) } }; @@ -984,7 +999,6 @@ impl Grant { match self.info.provider { Provider::PhysBorrowed { ref mut base, .. } => *base = base.next_by(middle_page_offset), - // TODO: Adjust cow_file_ref offset Provider::FmapBorrowed { ref mut file_ref } | Provider::Allocated { cow_file_ref: Some(ref mut file_ref) } => file_ref.base_offset += middle_page_offset * PAGE_SIZE, Provider::Allocated { cow_file_ref: None } | Provider::External { .. } => (), } @@ -997,7 +1011,6 @@ impl Grant { mapped: self.info.mapped, page_count: span.count, provider: match self.info.provider { - // TODO: Adjust offset Provider::Allocated { cow_file_ref: None } => Provider::Allocated { cow_file_ref: None }, Provider::Allocated { cow_file_ref: Some(ref file_ref) } => Provider::Allocated { cow_file_ref: Some(GrantFileRef { base_offset: file_ref.base_offset + this_span.count * PAGE_SIZE, @@ -1278,14 +1291,14 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re return Err(PfError::Segv); }; - let (_, flush) = correct_inner(addr_space_lock, faulting_page, access, 0)?; + let lock = &addr_space_lock; + let (_, flush, _) = correct_inner(lock, lock.write(), faulting_page, access, 0)?; flush.flush(); Ok(()) } -fn correct_inner(addr_space_lock: Arc>, faulting_page: Page, access: AccessMode, recursion_level: u32) -> Result<(Frame, PageFlush), PfError> { - let mut addr_space_guard = addr_space_lock.write(); +fn correct_inner<'l>(addr_space_lock: &'l RwLock, mut addr_space_guard: RwLockWriteGuard<'l, AddrSpace>, faulting_page: Page, access: AccessMode, recursion_level: u32) -> Result<(Frame, PageFlush, RwLockWriteGuard<'l, AddrSpace>), PfError> { let mut addr_space = &mut *addr_space_guard; let Some((grant_base, grant_info)) = addr_space.grants.contains(faulting_page) else { @@ -1384,7 +1397,8 @@ fn correct_inner(addr_space_lock: Arc>, faulting_page: Page, a drop(guard); drop(addr_space_guard); - let (frame, _) = correct_inner(foreign_address_space_lock, src_page, AccessMode::Read, new_recursion_level)?; + let ext_addrspace = &foreign_address_space_lock; + let (frame, _, _) = correct_inner(ext_addrspace, ext_addrspace.write(), src_page, AccessMode::Read, new_recursion_level)?; addr_space_guard = addr_space_lock.write(); addr_space = &mut *addr_space_guard; @@ -1449,16 +1463,19 @@ fn correct_inner(addr_space_lock: Arc>, faulting_page: Page, a return Err(PfError::Oom); }; - Ok((frame, flush)) + Ok((frame, flush, addr_space_guard)) } #[derive(Debug)] -pub enum MmapMode<'a> { - Cow(&'a mut PageMapper), - Shared(&'a PageMapper), +pub enum MmapMode { + Cow, + Shared, } pub struct BorrowedFmapSource<'a> { pub src_base: Page, - pub mode: MmapMode<'a>, + pub mode: MmapMode, + // TODO: There should be a method that obtains the lock from the guard. + pub addr_space_lock: &'a RwLock, + pub addr_space_guard: RwLockWriteGuard<'a, AddrSpace>, } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 20fb0e6e50..2939db90d9 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -832,7 +832,7 @@ impl KernelScheme for ProcScheme { } match self.handles.write().get_mut(&id).ok_or(Error::new(EBADF))?.data { - OperationData::Offset(ref mut offset) => *offset = dbg!(dbg!(*offset) + dbg!(grants_read)), + OperationData::Offset(ref mut offset) => *offset += grants_read, _ => return Err(Error::new(EBADFD)), }; diff --git a/src/scheme/user.rs b/src/scheme/user.rs index f354cf43e4..0c96651313 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -517,22 +517,20 @@ impl UserInner { base_offset: map.offset, }; - let src_read_guard; - let mut src_write_guard; - let src = match base_page_opt { Some(base_addr) => Some({ if base_addr % PAGE_SIZE != 0 { return Err(Error::new(EINVAL)); } + let addr_space_lock = &*src_address_space; BorrowedFmapSource { src_base: Page::containing_address(VirtualAddress::new(base_addr)), + addr_space_lock, + addr_space_guard: addr_space_lock.write(), mode: if map.flags.contains(MapFlags::MAP_SHARED) { - src_read_guard = src_address_space.read(); - MmapMode::Shared(&src_read_guard.table.utable) + MmapMode::Shared } else { - src_write_guard = src_address_space.write(); - MmapMode::Cow(&mut src_write_guard.table.utable) + MmapMode::Cow }, }