فهرست منبع

添加页面回收内核线程

MemoryShore 9 ماه پیش
والد
کامیت
d7e76ec720
6فایلهای تغییر یافته به همراه106 افزوده شده و 32 حذف شده
  1. 1 1
      kernel/Cargo.toml
  2. 2 16
      kernel/src/arch/x86_64/mm/mod.rs
  3. 2 0
      kernel/src/init/initcall.rs
  4. 3 3
      kernel/src/mm/fault.rs
  5. 7 1
      kernel/src/mm/init.rs
  6. 91 11
      kernel/src/mm/page.rs

+ 1 - 1
kernel/Cargo.toml

@@ -88,4 +88,4 @@ debug = true   # Controls whether the compiler passes `-g`
 
 # The release profile, used for `cargo build --release`
 [profile.release]
-debug = false
+debug = true

+ 2 - 16
kernel/src/arch/x86_64/mm/mod.rs

@@ -28,7 +28,7 @@ use crate::{
 };
 
 use crate::mm::kernel_mapper::KernelMapper;
-use crate::mm::page::{page_manager_lock_irqsave, EntryFlags, PageEntry, PAGE_1G_SHIFT};
+use crate::mm::page::{EntryFlags, PageEntry, PAGE_1G_SHIFT};
 use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags};
 
 use system_error::SystemError;
@@ -740,21 +740,7 @@ impl FrameAllocator for LockedFrameAllocator {
     unsafe fn allocate(&mut self, mut count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
         count = count.next_power_of_two();
         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
-            let usage = self.usage();
-            if usage.used().data() + count.data() > usage.total().data() / 2 {
-                log::info!("shrink: {:?}", usage);
-                let mut page_manager_guard = page_manager_lock_irqsave();
-                // 释放部分页面
-                page_manager_guard.shrink_list(count);
-            }
-            allocator.allocate(count)
-            // // 首次分配时内存不足
-            // allocator.allocate(count).or_else(|| {
-            //     let mut page_manager_guard = page_manager_lock_irqsave();
-            //     // 释放部分页面并再次尝试分配
-            //     page_manager_guard.shrink_list(count);
-            //     return allocator.allocate(count);
-            // })
+            return allocator.allocate(count);
         } else {
             return None;
         }

+ 2 - 0
kernel/src/init/initcall.rs

@@ -10,6 +10,7 @@ define_public_unified_initializer_slice!(INITCALL_FS);
 define_public_unified_initializer_slice!(INITCALL_ROOTFS);
 define_public_unified_initializer_slice!(INITCALL_DEVICE);
 define_public_unified_initializer_slice!(INITCALL_LATE);
+define_public_unified_initializer_slice!(INITCALL_MM);
 
 pub fn do_initcalls() -> Result<(), SystemError> {
     unified_init!(INITCALL_PURE);
@@ -21,5 +22,6 @@ pub fn do_initcalls() -> Result<(), SystemError> {
     unified_init!(INITCALL_ROOTFS);
     unified_init!(INITCALL_DEVICE);
     unified_init!(INITCALL_LATE);
+    unified_init!(INITCALL_MM);
     return Ok(());
 }

+ 3 - 3
kernel/src/mm/fault.rs

@@ -22,7 +22,7 @@ use crate::mm::MemoryManagementArch;
 
 use super::{
     allocator::page_frame::FrameAllocator,
-    page::{Page, PageFlags},
+    page::{page_reclaimer_lock_irqsave, Page, PageFlags},
 };
 
 bitflags! {
@@ -605,7 +605,6 @@ impl PageFaultHandler {
         let page_cache = file.inode().page_cache().unwrap();
         let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
         let mut ret = VmFaultReason::empty();
-        let mut page_manager_guard = page_manager_lock_irqsave();
 
         if let Some(page) = page_cache.get_page(file_pgoff) {
             // TODO 异步从磁盘中预读页面进PageCache
@@ -634,7 +633,8 @@ impl PageFaultHandler {
             pfm.page = Some(page.clone());
 
             page.write().add_flags(PageFlags::PG_LRU);
-            page_manager_guard.insert(new_cache_page, &page);
+            page_manager_lock_irqsave().insert(new_cache_page, &page);
+            page_reclaimer_lock_irqsave().insert_page(new_cache_page, &page);
             page_cache.add_page(file_pgoff, &page);
 
             page.write()

+ 7 - 1
kernel/src/mm/init.rs

@@ -8,7 +8,11 @@ use crate::{
     filesystem::procfs::kmsg::kmsg_init,
     ipc::shm::shm_manager_init,
     libs::printk::PrintkWriter,
-    mm::{allocator::slab::slab_init, mmio_buddy::mmio_init, page::page_manager_init},
+    mm::{
+        allocator::slab::slab_init,
+        mmio_buddy::mmio_init,
+        page::{page_manager_init, page_reclaimer_init},
+    },
 };
 
 use super::MemoryManagementArch;
@@ -57,6 +61,8 @@ pub unsafe fn mm_init() {
     page_manager_init();
     // enable SHM_MANAGER
     shm_manager_init();
+    // enable PAGE_RECLAIMER
+    page_reclaimer_init();
 
     MM_INIT
         .compare_exchange(

+ 91 - 11
kernel/src/mm/page.rs

@@ -1,3 +1,4 @@
+use alloc::string::ToString;
 use core::{
     fmt::{self, Debug, Error, Formatter},
     marker::PhantomData,
@@ -5,6 +6,8 @@ use core::{
     ops::Add,
     sync::atomic::{compiler_fence, Ordering},
 };
+use system_error::SystemError;
+use unified_init::macros::unified_init;
 
 use alloc::sync::Arc;
 use hashbrown::{HashMap, HashSet};
@@ -12,14 +15,17 @@ use log::{error, info};
 use lru::LruCache;
 
 use crate::{
-    arch::{interrupt::ipi::send_ipi, MMArch},
+    arch::{interrupt::ipi::send_ipi, mm::LockedFrameAllocator, MMArch},
     exception::ipi::{IpiKind, IpiTarget},
     filesystem::vfs::{file::PageCache, FilePrivateData},
+    init::initcall::INITCALL_MM,
     ipc::shm::ShmId,
     libs::{
         rwlock::RwLock,
         spinlock::{SpinLock, SpinLockGuard},
     },
+    process::{ProcessControlBlock, ProcessManager},
+    time::{sleep::usleep, PosixTimeSpec},
 };
 
 use super::{
@@ -59,14 +65,12 @@ pub fn page_manager_lock_irqsave() -> SpinLockGuard<'static, PageManager> {
 // 物理页管理器
 pub struct PageManager {
     phys2page: HashMap<PhysAddr, Arc<Page>>,
-    lru: LruCache<PhysAddr, Arc<Page>>,
 }
 
 impl PageManager {
     pub fn new() -> Self {
         Self {
             phys2page: HashMap::new(),
-            lru: LruCache::unbounded(),
         }
     }
 
@@ -75,12 +79,12 @@ impl PageManager {
     }
 
     pub fn get(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
-        self.lru.promote(paddr);
+        page_reclaimer_lock_irqsave().get(paddr);
         self.phys2page.get(paddr).cloned()
     }
 
     pub fn get_unwrap(&mut self, paddr: &PhysAddr) -> Arc<Page> {
-        self.lru.promote(paddr);
+        page_reclaimer_lock_irqsave().get(paddr);
         self.phys2page
             .get(paddr)
             .unwrap_or_else(|| panic!("Phys Page not found, {:?}", paddr))
@@ -89,19 +93,89 @@ impl PageManager {
 
     pub fn insert(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
         self.phys2page.insert(paddr, page.clone());
-        if page.read().flags.contains(PageFlags::PG_LRU) {
-            self.lru.put(paddr, page.clone());
-        }
     }
 
     pub fn remove_page(&mut self, paddr: &PhysAddr) {
         self.phys2page.remove(paddr);
     }
+}
+
+pub static mut PAGE_RECLAIMER: Option<SpinLock<PageReclaimer>> = None;
+
+pub fn page_reclaimer_init() {
+    info!("page_reclaimer_init");
+    let page_reclaimer = SpinLock::new(PageReclaimer::new());
+
+    compiler_fence(Ordering::SeqCst);
+    unsafe { PAGE_RECLAIMER = Some(page_reclaimer) };
+    compiler_fence(Ordering::SeqCst);
+
+    info!("page_reclaimer_init done");
+}
+
+static mut PAGE_RECLAIMER_THREAD: Option<Arc<ProcessControlBlock>> = None;
+
+#[unified_init(INITCALL_MM)]
+fn page_reclaimer_thread_init() -> Result<(), SystemError> {
+    let closure = crate::process::kthread::KernelThreadClosure::StaticEmptyClosure((
+        &(page_reclaim_thread as fn() -> i32),
+        (),
+    ));
+    let pcb = crate::process::kthread::KernelThreadMechanism::create_and_run(
+        closure,
+        "page_reclaim".to_string(),
+    )
+    .ok_or("")
+    .expect("create tty_refresh thread failed");
+    unsafe {
+        PAGE_RECLAIMER_THREAD = Some(pcb);
+    }
+    Ok(())
+}
+
+fn page_reclaim_thread() -> i32 {
+    loop {
+        let usage = unsafe { LockedFrameAllocator.usage() };
+        // log::info!("usage{:?}", usage);
+
+        // 保留4096个页面,总计16MB的空闲空间
+        if usage.free().data() < 4096 {
+            let page_to_free = 4096;
+            page_reclaimer_lock_irqsave().shrink_list(PageFrameCount::new(page_to_free));
+        } else {
+            // 休眠5秒
+            // log::info!("sleep");
+            let _ = usleep(PosixTimeSpec::new(5, 0));
+        }
+    }
+}
+
+pub fn page_reclaimer_lock_irqsave() -> SpinLockGuard<'static, PageReclaimer> {
+    unsafe { PAGE_RECLAIMER.as_ref().unwrap().lock_irqsave() }
+}
+
+pub struct PageReclaimer {
+    lru: LruCache<PhysAddr, Arc<Page>>,
+}
+
+impl PageReclaimer {
+    pub fn new() -> Self {
+        Self {
+            lru: LruCache::unbounded(),
+        }
+    }
+
+    pub fn get(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
+        self.lru.get(paddr).cloned()
+    }
+
+    pub fn insert_page(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
+        self.lru.put(paddr, page.clone());
+    }
 
     pub fn shrink_list(&mut self, count: PageFrameCount) {
         for _ in 0..count.data() {
-            let entry = self.lru.pop_lru().unwrap();
-            let page = entry.1.clone();
+            let (paddr, page) = self.lru.pop_lru().expect("pagecache is empty");
             let page_cache = page.read().page_cache().unwrap();
             for vma in page.read().anon_vma() {
                 let address_space = vma.lock().address_space().unwrap();
@@ -114,6 +188,7 @@ impl PageManager {
                 }
             }
             page_cache.remove_page(page.read().index().unwrap());
+            page_manager_lock_irqsave().remove_page(&paddr);
             if page.read().flags.contains(PageFlags::PG_DIRTY) {
                 //TODO 回写页面
                 let inode = page
@@ -143,6 +218,11 @@ impl PageManager {
             }
         }
     }
+
+    pub fn wakeup_claim_thread() {
+        log::info!("wakeup_claim_thread");
+        let _ = ProcessManager::wakeup(unsafe { PAGE_RECLAIMER_THREAD.as_ref().unwrap() });
+    }
 }
 
 bitflags! {
@@ -1058,7 +1138,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
         if !page_manager_guard.contains(&phys) {
             page_manager_guard.insert(phys, &Arc::new(Page::new(false, phys)))
         }
-
+        drop(page_manager_guard);
         return self.map_phys(virt, phys, flags);
     }