Special treat VM Space clearing

This commit is contained in:
Zhang Junyang 2024-11-03 15:34:30 +08:00 committed by Tate, Hongliang Tian
parent fda05e9e23
commit c34706603a
4 changed files with 71 additions and 13 deletions

View File

@ -339,8 +339,7 @@ impl Vmar_ {
}
fn clear_vm_space(&self) {
let mut cursor = self.vm_space.cursor_mut(&(0..ROOT_VMAR_CAP_ADDR)).unwrap();
cursor.unmap(ROOT_VMAR_CAP_ADDR);
self.vm_space.clear().unwrap();
}
pub fn destroy(&self, range: Range<usize>) -> Result<()> {

View File

@ -76,10 +76,7 @@ use super::{
use crate::{
mm::{
kspace::should_map_as_tracked,
page::{
meta::{MapTrackingStatus, PageTablePageMeta},
DynPage, Page,
},
page::{meta::MapTrackingStatus, DynPage},
Paddr, PageProperty, Vaddr,
},
task::{disable_preempt, DisabledPreemptGuard},
@ -593,8 +590,11 @@ where
continue;
}
// Go down if not applicable.
if cur_va % page_size::<C>(cur_level) != 0 || cur_va + page_size::<C>(cur_level) > end {
// Go down if not applicable or if the entry points to a child page table.
if cur_entry.is_node()
|| cur_va % page_size::<C>(cur_level) != 0
|| cur_va + page_size::<C>(cur_level) > end
{
let child = cur_entry.to_owned();
match child {
Child::PageTable(pt) => {
@ -645,10 +645,7 @@ where
prop,
}
}
Child::PageTable(node) => PageTableItem::PageTableNode {
page: Page::<PageTablePageMeta<E, C>>::from(node).into(),
},
Child::None => unreachable!(),
Child::PageTable(_) | Child::None => unreachable!(),
};
}

View File

@ -92,6 +92,26 @@ impl PageTable<UserMode> {
self.root.activate();
}
}
/// Clear the page table.
///
/// # Safety
///
/// The caller must ensure that:
/// 1. No other cursors are accessing the page table.
/// 2. No other CPUs activates the page table.
pub(in crate::mm) unsafe fn clear(&self) {
let mut root_node = self.root.clone_shallow().lock();
const NR_PTES_PER_NODE: usize = nr_subpage_per_huge::<PagingConsts>();
for i in 0..NR_PTES_PER_NODE / 2 {
let root_entry = root_node.entry(i);
if !root_entry.is_none() {
let old = root_entry.replace(Child::None);
// Since no others are accessing the old child, dropping it is fine.
drop(old);
}
}
}
}
impl PageTable<KernelMode> {

View File

@ -12,7 +12,9 @@
use core::{ops::Range, sync::atomic::Ordering};
use crate::{
arch::mm::{current_page_table_paddr, PageTableEntry, PagingConsts},
arch::mm::{
current_page_table_paddr, tlb_flush_all_excluding_global, PageTableEntry, PagingConsts,
},
cpu::{AtomicCpuSet, CpuExceptionInfo, CpuSet, PinCurrentCpu},
cpu_local_cell,
mm::{
@ -64,6 +66,35 @@ impl VmSpace {
}
}
/// Clears the user space mappings in the page table.
///
/// This method returns error if the page table is activated on any other
/// CPUs or there are any cursors alive.
pub fn clear(&self) -> core::result::Result<(), VmSpaceClearError> {
let preempt_guard = disable_preempt();
let _guard = self
.activation_lock
.try_write()
.ok_or(VmSpaceClearError::CursorsAlive)?;
let cpus = self.cpus.load();
let cpu = preempt_guard.current_cpu();
let cpus_set_is_empty = cpus.is_empty();
let cpus_set_is_single_self = cpus.count() == 1 && cpus.contains(cpu);
if cpus_set_is_empty || cpus_set_is_single_self {
// SAFETY: We have ensured that the page table is not activated on
// other CPUs and no cursors are alive.
unsafe { self.pt.clear() };
if cpus_set_is_single_self {
tlb_flush_all_excluding_global();
}
Ok(())
} else {
Err(VmSpaceClearError::PageTableActivated(cpus))
}
}
/// Gets an immutable cursor in the virtual address range.
///
/// The cursor behaves like a lock guard, exclusively owning a sub-tree of
@ -195,6 +226,17 @@ impl Default for VmSpace {
}
}
/// An error that may occur when doing [`VmSpace::clear`].
#[derive(Debug)]
pub enum VmSpaceClearError {
/// The page table is activated on other CPUs.
///
/// The activated CPUs detected are contained in the error.
PageTableActivated(CpuSet),
/// There are still cursors alive.
CursorsAlive,
}
/// The cursor for querying over the VM space without modifying it.
///
/// It exclusively owns a sub-tree of the page table, preventing others from