Skip to content

Commit 29e3ba3

Browse files
committed
memory/pmm: Merge regions when freeing
1 parent e7c261b commit 29e3ba3

1 file changed

Lines changed: 63 additions & 13 deletions

File tree

kernel/src/memory/pmm.rs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,64 @@ static PMM: SpinMutex<Pmm> = SpinMutex::new(Pmm {
6868
pages: &mut [],
6969
});
7070

71+
impl Pmm {
72+
fn free_region(&mut self, idx: usize, pages: usize) {
73+
debug_assert!(pages > 0);
74+
debug_assert!(self.pages[idx].count == 0);
75+
76+
let mut prev: Option<usize> = None;
77+
let mut cur = self.head;
78+
while cur != NO_PAGE && cur < idx {
79+
prev = Some(cur);
80+
cur = self.pages[cur].next;
81+
}
82+
let next = if cur == NO_PAGE { None } else { Some(cur) };
83+
debug_assert!(next != Some(idx));
84+
85+
// The previous region ends exactly where this one starts.
86+
if let Some(p) = prev
87+
&& p + self.pages[p].count == idx
88+
{
89+
self.pages[p].count += pages;
90+
self.pages[idx].next = NO_PAGE;
91+
92+
// Having grown `p`, it may now also be adjacent to `next`.
93+
if let Some(n) = next
94+
&& p + self.pages[p].count == n
95+
{
96+
self.pages[p].count += self.pages[n].count;
97+
self.pages[p].next = self.pages[n].next;
98+
self.pages[n].count = 0;
99+
self.pages[n].next = NO_PAGE;
100+
}
101+
return;
102+
}
103+
104+
if let Some(n) = next
105+
&& idx + pages == n
106+
{
107+
let n_count = self.pages[n].count;
108+
let n_next = self.pages[n].next;
109+
self.pages[idx].count = pages + n_count;
110+
self.pages[idx].next = n_next;
111+
self.pages[n].count = 0;
112+
self.pages[n].next = NO_PAGE;
113+
match prev {
114+
Some(p) => self.pages[p].next = idx,
115+
None => self.head = idx,
116+
}
117+
return;
118+
}
119+
120+
self.pages[idx].count = pages;
121+
self.pages[idx].next = next.unwrap_or(NO_PAGE);
122+
match prev {
123+
Some(p) => self.pages[p].next = idx,
124+
None => self.head = idx,
125+
}
126+
}
127+
}
128+
71129
pub struct KernelAlloc;
72130
impl KernelAlloc {
73131
fn dealloc_inner(addr: PhysAddr, pages: usize) {
@@ -78,15 +136,11 @@ impl KernelAlloc {
78136

79137
let mut pmm = PMM.lock();
80138
let idx = Page::idx_from_addr(addr);
81-
let old_head = pmm.head;
82-
let page = pmm.pages.get_mut(idx).unwrap();
83139

84-
debug_assert!(page.count == 0);
85-
debug_assert!(page.next == NO_PAGE);
140+
debug_assert!(pmm.pages[idx].count == 0);
141+
debug_assert!(pmm.pages[idx].next == NO_PAGE);
86142

87-
page.count = pages;
88-
page.next = old_head;
89-
pmm.head = idx;
143+
pmm.free_region(idx, pages);
90144
}
91145
}
92146

@@ -141,7 +195,6 @@ impl PageAllocator for KernelAlloc {
141195
break;
142196
}
143197

144-
// TODO: Merge adjacent regions if we didn't find anything.
145198
debug_assert!(addr.is_some());
146199

147200
match addr {
@@ -201,11 +254,8 @@ pub fn init(memory_map: &[PhysMemory], pages: &'static mut [Page]) {
201254
}
202255

203256
let idx = Page::idx_from_addr(entry.address);
204-
let old_head = pmm.head;
205-
let page = pmm.pages.get_mut(idx).unwrap();
206-
page.count = entry.length / arch::virt::get_page_size();
207-
page.next = old_head;
208-
pmm.head = idx;
257+
let count = entry.length / arch::virt::get_page_size();
258+
pmm.free_region(idx, count);
209259

210260
total_memory += entry.length;
211261
}

0 commit comments

Comments
 (0)