diff --git a/src/context/memory.rs b/src/context/memory.rs index 53e99e2cf1ce37e61b3b59c44dd1eae941b95da5..09e0f4027b5310b2765aaf65c0eebf0930a90c38 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 cae5b662fcfaca5106559fab6dd10bf1bf964d6d..9e0b8874641d2c90c7c8c4ec641196dcde96d334 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