From da6f6a316c7e08976b69392f0a00917c0b8f66ae Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Sun, 2 Jul 2023 15:01:14 +0200
Subject: [PATCH] Return only one grant, External, for Grant::borrow.

---
 src/arch/x86_64/paging/mod.rs |  4 +-
 src/context/memory.rs         | 74 ++++++++++++-----------------------
 src/scheme/proc.rs            |  2 +-
 src/scheme/user.rs            |  2 +-
 4 files changed, 31 insertions(+), 51 deletions(-)

diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs
index 54d53b9b..71598ea1 100644
--- a/src/arch/x86_64/paging/mod.rs
+++ b/src/arch/x86_64/paging/mod.rs
@@ -177,7 +177,9 @@ pub fn page_fault_handler(stack: &mut InterruptStack, code: PageFaultError, faul
         match try_correcting_page_tables(faulting_page, mode) {
             Ok(()) => return Ok(()),
             Err(PfError::Oom) => todo!("oom"),
-            Err(PfError::Segv) => (),
+            Err(PfError::Segv) => {
+                log::error!("Failed to correct page tables");
+            },
             Err(PfError::NonfatalInternalError) => todo!(),
         }
     }
diff --git a/src/context/memory.rs b/src/context/memory.rs
index 908f31e5..557314c3 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -237,9 +237,6 @@ impl AddrSpace {
         }
     }
     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> {
-        self.mmap_multiple(page, page_count, flags, move |page, flags, mapper, flusher| Ok(Some(map(page, flags, mapper, flusher)?)))
-    }
-    pub fn mmap_multiple<I: IntoIterator<Item = Grant>>(&mut self, page: Option<Page>, page_count: NonZeroUsize, flags: MapFlags, map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<I>) -> 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)?;
 
@@ -256,10 +253,8 @@ impl AddrSpace {
             &mut inactive as &mut dyn Flusher<RmmA>
         };
 
-        let iter = map(selected_span.base, page_flags(flags), &mut self.table.utable, flusher)?;
-        for grant in iter {
-            self.grants.insert(grant);
-        }
+        let grant = map(selected_span.base, page_flags(flags), &mut self.table.utable, flusher)?;
+        self.grants.insert(grant);
 
         Ok(selected_span.base)
     }
@@ -572,9 +567,6 @@ pub enum Provider {
     PhysBorrowed { base: Frame },
 
     /// The memory is borrowed directly from another address space.
-    ///
-    /// Those grants will be pinned, and thus cannot be removed until they are unpinned, when this
-    /// grant is unmapped.
     External { address_space: Arc<RwLock<AddrSpace>>, src_base: Page },
 
     FmapBorrowed { file_ref: GrantFileRef },
@@ -696,7 +688,7 @@ impl Grant {
         dst_flusher: impl Flusher<RmmA>,
         eager: bool,
         allow_phys: bool,
-    ) -> Result<Vec<Grant>> {
+    ) -> Result<Grant> {
         /*
         if eager {
             for page in PageSpan::new(src_base, page_count) {
@@ -705,8 +697,6 @@ impl Grant {
         }
         */
 
-        let mut dst_grants = Vec::with_capacity(1);
-
         let src_span = PageSpan::new(src_base, page_count);
         let mut prev_span = None;
 
@@ -721,35 +711,6 @@ impl Grant {
                 log::warn!("Hole between grants, prev_span {:?} src_base {:?} grant base {:?} grant {:#?}", prev_span, src_base, src_grant_base, src_grant);
                 return Err(Error::new(EINVAL));
             }
-
-            let common_span = src_span.intersection(grant_span);
-            let offset_from_src_base = common_span.base.offset_from(src_base);
-
-            let grant_dst_base = dst_base.next_by(offset_from_src_base);
-
-            dst_grants.push(Grant {
-                base: grant_dst_base,
-                info: GrantInfo {
-                    page_count: common_span.count,
-                    flags,
-                    mapped: true,
-                    provider: match src_grant.provider {
-                        Provider::Allocated { .. } => Provider::External {
-                            src_base,
-                            address_space: Arc::clone(&src_address_space_lock),
-                        },
-                        Provider::PhysBorrowed { base: src_phys_base } => if allow_phys {
-                            Provider::PhysBorrowed {
-                                base: src_phys_base.next_by(offset_from_src_base),
-                            }
-                        } else {
-                            return Err(Error::new(EACCES));
-                        },
-                        Provider::External { ref address_space, src_base } => Provider::External { address_space: Arc::clone(address_space), src_base },
-                        Provider::FmapBorrowed { ref file_ref } => Provider::FmapBorrowed { file_ref: file_ref.clone() }
-                    }
-                },
-            });
         }
 
         let Some(last_span) = prev_span else {
@@ -762,7 +723,15 @@ impl Grant {
             return Err(Error::new(EINVAL));
         }
 
-        Ok(dst_grants)
+        Ok(Grant {
+            base: dst_base,
+            info: GrantInfo {
+                page_count,
+                flags,
+                mapped: true,
+                provider: Provider::External { address_space: src_address_space_lock, src_base }
+            },
+        })
     }
     // TODO: This is limited to one grant. Should it be (if some magic new proc: API is introduced)?
     pub fn cow(
@@ -1235,14 +1204,23 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re
             let guard = foreign_address_space.upgradeable_read();
             let src_page = src_base.next_by(pages_from_grant_start);
 
-            if let Some((phys, _)) = guard.table.utable.translate(src_page.start_address()) {
-                let src_frame = Frame::containing_address(phys);
+            if let Some(src_grant) = guard.grants.contains(src_page) {
+                if let Some((phys, _)) = guard.table.utable.translate(src_page.start_address()) {
+                    let src_frame = Frame::containing_address(phys);
 
-                let info = get_page_info(src_frame).expect("all allocated frames need a PageInfo");
-                info.add_ref(false);
+                    let info = get_page_info(src_frame).expect("all allocated frames need a PageInfo");
+                    info.add_ref(false);
 
-                src_frame
+                    src_frame
+                } else {
+                    // Grant was valid (TODO check), but we need to correct the underlying page.
+                    todo!()
+                }
             } else {
+                // Grant did not exist, but we did own a Provider::External mapping, and cannot
+                // simply let the current context fail. TODO: But all borrowed memory shouldn't
+                // really be lazy though?
+
                 let mut guard = RwLockUpgradableGuard::upgrade(guard);
 
                 // TODO: Should this be called?
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 9e910eb3..8324432b 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -717,7 +717,7 @@ impl KernelScheme for ProcScheme {
 
                     dst_addr_space.mmap(requested_dst_page, src_page_count, map.flags, |dst_page, _flags, dst_mapper, dst_flusher| Grant::transfer(middle, dst_page, src_mapper, dst_mapper, InactiveFlusher::new(), dst_flusher))?
                 } else {
-                    dst_addr_space.mmap_multiple(requested_dst_page, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), src_addr_space, src_grant_span.base, dst_page, src_grant_span.count, flags, dst_mapper, flusher, true, true)?))?
+                    dst_addr_space.mmap(requested_dst_page, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), src_addr_space, src_grant_span.base, dst_page, src_grant_span.count, flags, dst_mapper, flusher, true, true)?))?
                 };
 
                 Ok(result_base.start_address().data())
diff --git a/src/scheme/user.rs b/src/scheme/user.rs
index 9e8e7acb..b3c2d8fa 100644
--- a/src/scheme/user.rs
+++ b/src/scheme/user.rs
@@ -263,7 +263,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_multiple(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, 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
-- 
GitLab