Fix allocate_frames_complex

This commit is contained in:
4lDO2
2023-10-28 15:05:45 +02:00
parent 4fccc4b87b
commit c349e4cd83
+71 -23
View File
@@ -48,13 +48,16 @@ pub fn allocate_frame() -> Option<Frame> {
allocate_frames(1)
}
pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, min: usize) -> Option<(Frame, usize)> {
let before = get_freelist_pagecount();
//debug_freelist();
// TODO: Split into sub-power of two allocations.
let min_order = min.next_power_of_two().trailing_zeros();
let _req_order = count.next_power_of_two().trailing_zeros();
let mut freelist = FREELIST.lock();
let Some((frame_order, frame)) = freelist[min_order as usize..].iter().enumerate().find_map(|(i, f)| f.map(|f| (i, f))) else {
let Some((frame_order, frame)) = freelist.iter().enumerate().skip(min_order as usize).find_map(|(i, f)| f.map(|f| (i as u32, f))) else {
// TODO: For larger sizes than the max order, split into power of two allocations.
log::error!("COUNT {min}");
log::error!("FREELIST {freelist:#?}");
@@ -68,29 +71,32 @@ pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, mi
let next_free = info.next();
//log::info!("FREE {frame:?} ORDER {frame_order} NEXT_FREE {next_free:?}");
freelist[frame_order] = next_free.frame();
freelist[frame_order as usize] = next_free.frame();
// TODO: Is this LIFO cache optimal?
for order in (min..frame_order).rev() {
let order_page_count = 1 << (order - 1);
//log::info!("MIN{min_order}FRAMEORD{frame_order}");
for order in (min_order..frame_order).rev() {
//log::info!("SPLIT ORDER {order}");
let order_page_count = 1 << order;
let hi = frame.next_by(order_page_count);
//log::info!("SPLIT INTO {frame:?}:{hi:?} ORDER {order}");
if let Some(old_head) = freelist[order].replace(hi) {
if let Some(old_head) = freelist[order as usize].replace(hi) {
let hi_info = get_page_info(hi)
.expect("no page info for allocated frame")
.as_free().expect("freelist cannot contain used pages!");
hi_info.set_next(P2Frame::new(Some(old_head), order as u32));
hi_info.set_next(P2Frame::new(Some(old_head), order));
get_page_info(old_head).expect("freelist head needs page info")
.as_free().expect("freelist head cannot be in use")
.set_prev(P2Frame::new(Some(hi), order as u32));
.set_prev(P2Frame::new(Some(hi), order));
}
}
info.mark_used();
drop(freelist);
unsafe {
(RmmA::phys_to_virt(frame.start_address()).data() as *mut u8).write_bytes(0, PAGE_SIZE << min_order);
@@ -107,15 +113,33 @@ pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, mi
}
assert!(found);
}*/
let after = get_freelist_pagecount();
assert_eq!(after, before - (1 << min_order));
/*
if after != before - (1 << min_order) {
log::info!("BAD ALLOC order {min_order} frame {frame:?} after {after} before {before} frameorder {frame_order}");
debug_freelist();
loop {}
} else {
//log::info!("GOOD ALLOC order {min_order} frame {frame:?}");
}*/
Some((frame, PAGE_SIZE << min_order))
}
/// Deallocate a range of frames
pub unsafe fn deallocate_frames(frame: Frame, count: usize) {
let before = get_freelist_pagecount();
deallocate_frames_inner(frame, count);
let after = get_freelist_pagecount();
assert_eq!(before + count, after);
}
unsafe fn deallocate_frames_inner(frame: Frame, count: usize) {
if count == 0 {
log::warn!("Count == 0 (frame {frame:?}");
return;
}
//log::info!("DEALLOCATE {frame:?}+{count}");
let max_order = core::cmp::min(MAX_ORDER, count.next_power_of_two().trailing_zeros());
@@ -129,20 +153,40 @@ pub unsafe fn deallocate_frames(frame: Frame, count: usize) {
}).expect("must succeed at least for order=0");
for i in 0..number_of_chunks {
deallocate_p2frame(Frame::containing_address(PhysicalAddress::new(first_aligned + i * (PAGE_SIZE << chunk_order))), chunk_order);
let p2frame = Frame::containing_address(PhysicalAddress::new(first_aligned + i * (PAGE_SIZE << chunk_order)));
//log::info!("P2DEALLOCATE {frame:?}+2^{chunk_order}");
deallocate_p2frame(p2frame, chunk_order);
}
let first_aligned_frame = Frame::containing_address(PhysicalAddress::new(first_aligned));
let lo_subblock_page_count = first_aligned_frame.offset_from(frame);
let hi_subblock_page_count = count - (number_of_chunks << chunk_order) - lo_subblock_page_count;
if lo_subblock_page_count > 0 {
deallocate_frames(frame, lo_subblock_page_count);
//log::info!("SUBDEALLOCATE LO {frame:?}+{lo_subblock_page_count}");
deallocate_frames_inner(frame, lo_subblock_page_count);
}
if hi_subblock_page_count > 0 {
deallocate_frames(first_aligned_frame.next_by(number_of_chunks << chunk_order), hi_subblock_page_count);
let hi_frame = first_aligned_frame.next_by(number_of_chunks << chunk_order);
//log::info!("SUBDEALLOCATE HI {hi_frame:?}+{hi_subblock_page_count}");
deallocate_frames_inner(hi_frame, hi_subblock_page_count);
}
}
fn get_freelist_pagecount() -> usize {
let mut pagecount = 0;
let freelist = FREELIST.lock();
//log::info!("DEALLOCED {frame:?}+{count}");
for order in 0..=MAX_ORDER {
let Some(mut p2frame) = freelist[order as usize] else {
continue;
};
pagecount += 1 << order;
while let Some(next) = get_page_info(p2frame).unwrap().as_free().unwrap().next().frame() {
pagecount += 1 << order;
p2frame = next;
}
}
pagecount
}
unsafe fn deallocate_p2frame(mut frame: Frame, order: u32) {
@@ -631,21 +675,25 @@ fn init_sections(mut allocator: BumpAllocator<RmmA>) {
*FREELIST.lock() = first_pages.map(|pair| pair.map(|(frame, _)| frame));
{
let freelist = FREELIST.lock();
}
fn debug_freelist() {
let freelist = FREELIST.lock();
for order in 0..=MAX_ORDER {
let Some(first_frame) = freelist[order as usize] else {
continue;
};
//log::info!("ORDER {order} FIRST {first_frame:?}");
let mut frame = first_frame;
for order in 0..=MAX_ORDER {
let Some(first_frame) = freelist[order as usize] else {
continue;
};
log::info!("ORDER {order} FIRST {first_frame:?}");
let mut frame = first_frame;
while let Some(next) = get_page_info(frame).unwrap_or_else(|| panic!("no page info: {frame:?}")).as_free().expect("not free").next().frame() {
//log::info!("ORDER {order} THEN {next:?}");
frame = next;
}
if order == MAX_ORDER { break }
let mut count = 1;
while let Some(next) = get_page_info(frame).unwrap_or_else(|| panic!("no page info: {frame:?}")).as_free().expect("not free").next().frame() {
log::info!("ORDER {order} THEN {next:?}");
frame = next;
count += 1;
}
log::info!("ORDER {order}: {count} p2frames");
}
}