Fix significant memory leak.

This commit is contained in:
4lDO2
2024-07-24 21:59:50 +02:00
parent e7a46c3422
commit 49b94047a8
3 changed files with 73 additions and 44 deletions
+34 -29
View File
@@ -1425,9 +1425,8 @@ impl Grant {
}
src_flusher_state = src_flusher.detach();
if page_info.remove_ref().is_none() {
deallocate_frame(frame);
}
// TODO: there used to be an additional remove_ref here, was that
// correct?
new_cow_frame
},
@@ -2791,10 +2790,37 @@ pub struct NopFlusher;
impl GenericFlusher for NopFlusher {
fn queue(
&mut self,
_frame: Frame,
_phys_contiguous_count: Option<NonZeroUsize>,
_actions: TlbShootdownActions,
frame: Frame,
phys_contiguous_count: Option<NonZeroUsize>,
actions: TlbShootdownActions,
) {
if actions.contains(TlbShootdownActions::FREE) {
handle_free_action(frame, phys_contiguous_count);
}
}
}
fn handle_free_action(base: Frame, phys_contiguous_count: Option<NonZeroUsize>) {
if let Some(count) = phys_contiguous_count {
for i in 0..count.get() {
let new_rc = get_page_info(base.next_by(i))
.expect("phys_contiguous frames all need PageInfos")
.remove_ref();
assert_eq!(new_rc, None);
}
unsafe {
let order = count.get().next_power_of_two().trailing_zeros();
deallocate_p2frame(base, order);
}
} else {
let Some(info) = get_page_info(base) else {
return;
};
if info.remove_ref() == None {
unsafe {
deallocate_frame(base);
}
}
}
}
struct FlusherState<'addrsp> {
@@ -2848,7 +2874,7 @@ impl<'guard, 'addrsp> Flusher<'guard, 'addrsp> {
pub fn flush(&mut self) {
let pages = core::mem::take(&mut self.state.pagequeue);
if pages.is_empty() && core::mem::replace(&mut self.state.dirty, false) == true {
if pages.is_empty() && core::mem::replace(&mut self.state.dirty, false) == false {
return;
}
@@ -2883,28 +2909,7 @@ impl<'guard, 'addrsp> Flusher<'guard, 'addrsp> {
else {
continue;
};
if let Some(count) = phys_contiguous_count {
for i in 0..count.get() {
let new_rc = get_page_info(base.next_by(i))
.expect("phys_contiguous frames all need PageInfos")
.remove_ref();
assert_eq!(new_rc, None);
}
unsafe {
let order = count.get().next_power_of_two().trailing_zeros();
deallocate_p2frame(base, order);
}
} else {
let Some(info) = get_page_info(base) else {
continue;
};
if info.remove_ref() == None {
unsafe {
deallocate_frame(base);
}
}
}
handle_free_action(base, phys_contiguous_count);
}
}
}
+24 -15
View File
@@ -1,6 +1,8 @@
use alloc::collections::BTreeSet;
use crate::paging::{RmmA, RmmArch, TableKind, PAGE_SIZE};
use crate::{
context::Context,
paging::{RmmA, RmmArch, TableKind, PAGE_SIZE},
};
use spinning_top::RwSpinlock;
//TODO: combine arches into one function (aarch64 one is newest)
@@ -209,7 +211,10 @@ pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "x86_64")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
pub unsafe fn debugger(target_id: Option<*const RwSpinlock<Context>>) {
use core::sync::atomic::Ordering;
use alloc::sync::Arc;
use hashbrown::HashSet;
use crate::memory::{get_page_info, the_zeroed_frame, RefCount};
@@ -230,12 +235,12 @@ pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
let old_table = RmmA::table(TableKind::User);
for (id, context_lock) in crate::context::contexts().iter() {
if target_id.map_or(false, |target_id| *id != target_id) {
for context_lock in crate::context::contexts().iter() {
if target_id.map_or(false, |target_id| Arc::as_ptr(&context_lock.0) != target_id) {
continue;
}
let context = context_lock.read();
println!("{}: {}", (*id).get(), context.name);
let context = context_lock.0.read();
println!("{:p}: {}", Arc::as_ptr(&context_lock.0), context.name);
if let Some(ref head) = context.syscall_head {
tree.insert(head.get(), (1, false));
@@ -320,22 +325,26 @@ pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
println!();
}
crate::scheme::proc::foreach_addrsp(|addrsp| {
let was_new = spaces.insert(addrsp.acquire_read().table.utable.table().phys().data());
check_consistency(&mut *addrsp.acquire_write(), was_new, &mut tree);
});
for (frame, (count, p)) in tree {
let Some(info) = get_page_info(frame) else {
assert!(p);
continue;
};
let rc = info.refcount();
let c = match rc {
None => 0,
Some(RefCount::One) => 1,
Some(RefCount::Cow(c)) => c.get(),
Some(RefCount::Shared(s)) => s.get(),
let (c, s) = match rc {
None => (0, false),
Some(RefCount::One) => (1, false),
Some(RefCount::Cow(c)) => (c.get(), false),
Some(RefCount::Shared(s)) => (s.get(), true),
};
if c != count {
println!(
"frame refcount mismatch for {:?} ({} != {})",
frame, c, count
"frame refcount mismatch for {:?} ({} != {} s {})",
frame, c, count, s
);
}
}
+15
View File
@@ -235,6 +235,21 @@ static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
// Using BTreeMap as hashbrown doesn't have a const constructor.
static HANDLES: RwLock<BTreeMap<usize, Handle>> = RwLock::new(BTreeMap::new());
#[cfg(feature = "debugger")]
#[allow(dead_code)]
pub fn foreach_addrsp(mut f: impl FnMut(&Arc<AddrSpaceWrapper>)) {
for (_, handle) in HANDLES.read().iter() {
let Handle::Context {
kind: ContextHandle::AddrSpace { addrspace, .. },
..
} = handle
else {
continue;
};
f(&addrspace);
}
}
fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalFlags)> {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
let _ = HANDLES.write().insert(id, handle);