Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multipage Deallocator #19

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 94 additions & 14 deletions fs/hayleyfs/balloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,19 +260,21 @@ impl PageAllocator for Option<PerCpuPageAllocator> {

fn dealloc_data_page_list(&self, pages: &DataPageListWrapper<Clean, Free>) -> Result<()> {
if let Some(allocator) = self {
let mut page_list = pages.get_page_list_cursor();
let mut page = page_list.current();
while page.is_some() {
// janky syntax to deal with the fact that page_list.current() returns an Option
if let Some(page) = page {
// TODO: refactor to avoid acquiring lock on every iteration
allocator.dealloc_page(page.get_page_no())?;
page_list.move_next();
} else {
unreachable!()
}
page = page_list.current();
}
let page_list = pages.get_page_list_cursor();
// let mut page = page_list.current();
// while page.is_some() {
// // janky syntax to deal with the fact that page_list.current() returns an Option
// if let Some(page) = page {
// // TODO: refactor to avoid acquiring lock on every iteration
// allocator.dealloc_page(page.get_page_no())?;
// page_list.move_next();
// } else {
// unreachable!()
// }
// page = page_list.current();
// }
// Ok(())
allocator.dealloc_multiple_page(page_list)?;
Ok(())
} else {
pr_info!("ERROR: page allocator is uninitialized\n");
Expand All @@ -292,6 +294,7 @@ impl PageAllocator for Option<PerCpuPageAllocator> {

fn dealloc_dir_page_list(&self, pages: &DirPageListWrapper<Clean, Free>) -> Result<()> {
if let Some(allocator) = self {
let page_list = pages.get_page_list_cursor();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line, since we obtain the cursor for the list on the next line.

let mut page_list = pages.get_page_list_cursor();
let mut page = page_list.current();
while page.is_some() {
Expand Down Expand Up @@ -343,6 +346,83 @@ impl PerCpuPageAllocator {
Ok(())
}
}


fn dealloc_multiple_page(&self, mut page_list : Cursor<'_, Box<LinkedPage>>) -> Result<()> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cleaner to move this code into dealloc_data_page_list so that we don't have to pass a Cursor type around.

// hash map to store free list lock for every cpu
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused by this comment -- it stores the free list for each CPU, not the lock, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. I made sure to change the comment.

let mut cpu_free_list_map : RBTree<usize, Vec<PageNum>> = RBTree::new();


let mut page = page_list.current(); // head of page list

let mut num_pages = 0;

// get a list of pages #s for each cpu
while page.is_some() {
if let Some(page) = page {
pr_info!("Page: {}", page.get_page_no());

let cpu : usize = ((page.get_page_no() - self.start) / self.pages_per_cpu).try_into()?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be a function defined elsewhere to do this calculation (if not, we should make one).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go ahead and make a helper function to do this calculation.


if matches!(cpu_free_list_map.get(&cpu), None) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are only matching against one pattern, and it's the Option type, it would be more idiomatic/cleaner to do if cpu_free_list_map.get(&cpu).is_none().

cpu_free_list_map.try_insert(cpu, Vec::new())?;
}

// add cpu page to vector (vector is mutable)
let cpu_page_vec : &mut Vec<PageNum> = cpu_free_list_map.get_mut(&cpu).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ? rather than unwrap here -- even though this should always succeed, it's safer to avoid using unwrap wherever possible, since the kernel will panic and crash if we call unwrap on an error.

Copy link
Collaborator Author

@DevonSchwartz DevonSchwartz Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I change it to ?, I get the following compiler error:

"cannot use the ? operator in a method that returns `core::result::Result<(), kernel::Err

Update: I think I made the unwrap safe by calling is_some() on the option returned by the get_mut() function


cpu_page_vec.try_push(page.get_page_no())?;

page_list.move_next();
}
page = page_list.current();
num_pages += 1;
}

pr_info!("Num Pages in List: {}", num_pages);

// add pages to corresponding free list in ascending cpu # order
for (cpu, page_nos) in cpu_free_list_map.iter() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure -- have you confirmed/checked that this always iterates over the CPU keys in ascending order?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed through dmesg that this iterates over CPU keys in ascending order (I think the RB tree default is ascending), but I don't know how to formally test it, so I'll remove the comment.


let free_list = Arc::clone(&self.free_lists[*cpu]);
let mut free_list = free_list.lock();
let old_free_pages = free_list.free_pages;

for page_no in page_nos.iter() {

free_list.free_pages += 1;
let res = free_list.list.try_insert(*page_no, ());

// unwrap the error so we can get at the option
let res = match res {
Ok(res) => res,
Err(e) => {
pr_info!(
"ERROR: failed to insert {:?} into page allocator at CPU {:?}, error {:?}\n",
page_no,
cpu,
e
);
return Err(e);
}
};

// check that the page was not already present in the tree. CAUSING ERRORS DUE TO TYPE ANNOTATION ISSUES
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What error is this running into?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to resolve that error but forgot to delete the comment. I'll make sure to delete it.

if res.is_some() {
pr_info!(
"ERROR: page {:?} was already in the allocator at CPU {:?}\n",
page_no,
cpu
);
return Err(EINVAL);
}
pr_info!("Cpu: {} Freed: {}", cpu, page_no);
pr_info!("Pages Added: {}", free_list.free_pages - old_free_pages);
}
}

return Ok(());
}
}

// placeholder page descriptor that can represent either a dir or data page descriptor
Expand Down Expand Up @@ -2365,4 +2445,4 @@ impl<Op> DataPageListWrapper<InFlight, Op> {
pages: self.pages,
}
}
}
}