Fix significant memory leak.
This commit is contained in:
+34
-29
@@ -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
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user