From e9751585fe0e12dc3d140ad7dfb60be7470db551 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sun, 7 Apr 2024 00:21:13 +0800 Subject: [PATCH] fix: allocator: freelist: reserve is not handling overlapped situations --- kernel/src/vspace/addr.rs | 16 ++++++- kernel/src/vspace/allocator/freelist.rs | 56 ++++++++++++++++--------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/kernel/src/vspace/addr.rs b/kernel/src/vspace/addr.rs index fddc366..dd586cf 100644 --- a/kernel/src/vspace/addr.rs +++ b/kernel/src/vspace/addr.rs @@ -13,10 +13,10 @@ pub fn align_down(addr: usize, align: usize) -> usize { addr & !(align - 1) } -#[derive(Copy, Clone, Default, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct PhysAddr(pub usize); -#[derive(Copy, Clone, Default, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct VirtAddr(pub usize); pub trait AddressOps { @@ -227,6 +227,12 @@ impl From<*mut T> for PhysAddr { } } +impl From<*const T> for PhysAddr { + fn from(addr: *const T) -> Self { + PhysAddr(addr as usize) + } +} + impl From for usize { fn from(addr: PhysAddr) -> Self { addr.0 @@ -263,6 +269,12 @@ impl From<*mut T> for VirtAddr { } } +impl From<*const T> for VirtAddr { + fn from(addr: *const T) -> Self { + VirtAddr(addr as usize) + } +} + impl From for usize { fn from(addr: VirtAddr) -> Self { addr.0 diff --git a/kernel/src/vspace/allocator/freelist.rs b/kernel/src/vspace/allocator/freelist.rs index 5c20d84..76d52c7 100644 --- a/kernel/src/vspace/allocator/freelist.rs +++ b/kernel/src/vspace/allocator/freelist.rs @@ -3,6 +3,8 @@ use crate::utils::then::Then; use crate::vspace::addr::{AddressOps, PhysAddr}; use core::alloc::{GlobalAlloc, Layout}; +use core::cmp::{max, min}; +use core::fmt::Debug; use spin::Mutex; struct ListNode { @@ -42,12 +44,21 @@ impl ListNode { } } -struct FreeList { +impl Debug for ListNode { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("ListNode") + .field("begin", &self.start_addr()) + .field("end", &self.end_addr()) + .finish() + } +} + +pub struct FreeList { head: ListNode, } impl FreeList { - const fn new() -> Self { + pub const fn new() -> Self { Self { head: ListNode::new(0), } @@ -78,7 +89,7 @@ impl FreeList { (size, layout.align()) } - unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 { + pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 { let (size, align) = Self::align_layout(layout); if let Some((region, alloc_start)) = self.alloc_node(|region| region.fit(size, align)) { @@ -93,7 +104,7 @@ impl FreeList { } } - unsafe fn dealloc(&mut self, start: PhysAddr, size: usize) { + pub unsafe fn dealloc(&mut self, start: PhysAddr, size: usize) { assert_eq!(start.align_up(core::mem::align_of::()), start); assert!(size >= core::mem::size_of::()); @@ -105,33 +116,38 @@ impl FreeList { } pub fn reserve(&mut self, start: PhysAddr, size: usize) { - if let Some((region, _)) = - self.alloc_node(|region| (region.start_addr() <= start).and(|| region.fit(size, 1), ())) - { - /* layout - * region: | before | [start +: size] | after | - * ^ ^ ^ ^ region.end_addr() - * | | alloc_start | - * | | alloc_end - * | region.start_addr() - */ - + if let Some((region, _)) = self.alloc_node(|region| { + let left = max(region.start_addr(), start); + let right = min(region.end_addr(), start + size); + (left < right).some(|| (), ()) + }) { let region_start = region.start_addr(); let region_end = region.end_addr(); - let before_size = (start - region_start).as_usize(); - if before_size > 0 { - unsafe { self.dealloc(region_start, before_size) } - } - let after_size = (region_end - (start + size)).as_usize(); if after_size > 0 { unsafe { self.dealloc(start + size, after_size) } } + + let before_size = (start - region_start).as_usize(); + if before_size > 0 { + unsafe { self.dealloc(region_start, before_size) } + } } } } +impl Debug for FreeList { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let mut current = &self.head; + while let Some(ref region) = current.next { + write!(f, "{:?} -> ", region)?; + current = region; + } + write!(f, "None") + } +} + pub struct FreeListAllocator { list: Mutex, }