From 02f04752e8fb83a7592dd16026f47336af36ecfb Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Mon, 10 Jul 2023 11:39:29 +0200
Subject: [PATCH] Use proper locks for PageInfo.

---
 src/context/memory.rs | 33 +++++++++++++++++++++------------
 src/memory/mod.rs     | 10 ++++------
 2 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/src/context/memory.rs b/src/context/memory.rs
index 53e99e2c..09e0f402 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -780,7 +780,8 @@ impl Grant {
                 };
 
                 if let Some(page_info) = get_page_info(frame) {
-                    page_info.add_ref(false);
+                    let guard = page_info.lock();
+                    guard.add_ref(false);
                 }
 
                 unsafe {
@@ -909,7 +910,8 @@ impl Grant {
             };
 
             let src_page_info = get_page_info(src_frame).expect("allocated page was not present in the global page array");
-            src_page_info.add_ref(is_cow);
+            let guard = src_page_info.lock();
+            guard.add_ref(is_cow);
 
             let Some(map_result) = (unsafe { dst_mapper.map_phys(dst_page, src_frame.start_address(), flags.write(flags.has_write() && !is_cow)) }) else {
                 break;
@@ -990,7 +992,8 @@ impl Grant {
             };
 
             if let Some(info) = get_page_info(frame) {
-                if info.remove_ref(is_cow) == 0 {
+                let guard = info.lock();
+                if guard.remove_ref(is_cow) == 0 {
                     deallocate_frames(frame, 1);
                 };
             } else {
@@ -1330,8 +1333,9 @@ fn cow(dst_mapper: &mut PageMapper, page: Page, old_frame: Frame, info: &PageInf
 fn init_frame(init_rc: usize, init_borrowed_rc: usize) -> Result<Frame, PfError> {
     let new_frame = crate::memory::allocate_frames(1).ok_or(PfError::Oom)?;
     let page_info = get_page_info(new_frame).expect("all allocated frames need an associated page info");
-    page_info.refcount.store(init_rc, Ordering::Relaxed);
-    page_info.borrowed_refcount.store(init_borrowed_rc, Ordering::Relaxed);
+    let guard = page_info.lock();
+    guard.refcount.store(init_rc, Ordering::Relaxed);
+    guard.borrowed_refcount.store(init_borrowed_rc, Ordering::Relaxed);
 
     Ok(new_frame)
 }
@@ -1421,10 +1425,13 @@ fn correct_inner<'l>(addr_space_lock: &'l RwLock<AddrSpace>, mut addr_space_guar
         Provider::Allocated { .. } | Provider::AllocatedShared if access == AccessMode::Write => {
             match faulting_pageinfo_opt {
                 Some((_, None)) => unreachable!("allocated page needs frame to be valid"),
-                Some((frame, Some(info))) => if info.owned_refcount() == 1 {
-                    frame
-                } else {
-                    cow(&mut addr_space.table.utable, faulting_page, frame, info, grant_flags)?
+                Some((frame, Some(info_lock))) => {
+                    let guard = info_lock.lock();
+                    if guard.owned_refcount() == 1 {
+                        frame
+                    } else {
+                        cow(&mut addr_space.table.utable, faulting_page, frame, &*guard, grant_flags)?
+                    }
                 },
                 _ => map_zeroed(&mut addr_space.table.utable, faulting_page, grant_flags, true)?,
             }
@@ -1433,11 +1440,12 @@ fn correct_inner<'l>(addr_space_lock: &'l RwLock<AddrSpace>, mut addr_space_guar
         Provider::Allocated { .. } | Provider::AllocatedShared => {
             match faulting_pageinfo_opt {
                 Some((_, None)) => unreachable!("allocated page needs frame to be valid"),
-                Some((frame, Some(page_info))) => {
+                Some((frame, Some(page_info_lock))) => {
+                    let guard = page_info_lock.lock();
                     // Keep in mind that alloc_writable must always be true if this code is reached
                     // for AllocatedShared, since shared pages cannot be mapped lazily (without
                     // using AddrSpace backrefs).
-                    allow_writable = page_info.owned_refcount() == 1;
+                    allow_writable = guard.owned_refcount() == 1;
 
                     frame
                 }
@@ -1481,7 +1489,8 @@ fn correct_inner<'l>(addr_space_lock: &'l RwLock<AddrSpace>, mut addr_space_guar
                     frame
                 };
 
-                let info = get_page_info(src_frame).expect("all allocated frames need a PageInfo");
+                let info_lock = get_page_info(src_frame).expect("all allocated frames need a PageInfo");
+                let info = info_lock.lock();
                 info.add_ref(false);
 
                 src_frame
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index cae5b662..9e0b8874 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -20,7 +20,7 @@ use rmm::{
     FrameAllocator,
     FrameCount,
 };
-use spin::RwLock;
+use spin::{RwLock, Mutex};
 use crate::syscall::flag::{PartialAllocStrategy, PhysallocFlags};
 use crate::syscall::error::{ENOMEM, Error};
 
@@ -196,7 +196,6 @@ pub struct PageInfo {
     pub borrowed_refcount: AtomicUsize,
     // TODO: AtomicFlags?
     pub flags: FrameFlags,
-    pub _padding: usize,
 }
 
 bitflags::bitflags! {
@@ -213,7 +212,7 @@ pub static SECTIONS: RwLock<Vec<&'static Section>> = RwLock::new(Vec::new());
 
 pub struct Section {
     base: Frame,
-    frames: Box<[PageInfo]>,
+    frames: Box<[Mutex<PageInfo>]>,
 }
 
 pub const MAX_SECTION_SIZE_BITS: u32 = 27;
@@ -235,7 +234,7 @@ pub fn init_mm() {
             sections.push(Box::leak(Box::new(Section {
                 base,
                 // TODO: zeroed rather than PageInfo::new()?
-                frames: try_box_slice_new(PageInfo::new, section_page_count).expect("failed to allocate pages array"),
+                frames: try_box_slice_new(|| Mutex::new(PageInfo::new()), section_page_count).expect("failed to allocate pages array"),
             })) as &'static Section);
 
             pages_left -= section_page_count;
@@ -254,7 +253,6 @@ impl PageInfo {
             refcount: AtomicUsize::new(0),
             borrowed_refcount: AtomicUsize::new(0),
             flags: FrameFlags::NONE,
-            _padding: 0,
         }
     }
     pub fn add_ref(&self, cow: bool) {
@@ -278,7 +276,7 @@ impl PageInfo {
         self.refcount.load(Ordering::SeqCst) - self.borrowed_refcount.load(Ordering::SeqCst)
     }
 }
-pub fn get_page_info(frame: Frame) -> Option<&'static PageInfo> {
+pub fn get_page_info(frame: Frame) -> Option<&'static Mutex<PageInfo>> {
     let sections = SECTIONS.read();
 
     let idx = sections
-- 
GitLab