瀏覽代碼

添加shrink_list方法释放页面

MemoryShore 9 月之前
父節點
當前提交
a6ff58c145

+ 1 - 0
kernel/Cargo.toml

@@ -55,6 +55,7 @@ paste = "=1.0.14"
 slabmalloc = { path = "crates/rust-slabmalloc" }
 log = "0.4.21"
 xarray = "0.1.0"
+lru = "0.12.3"
 
 # target为x86_64时,使用下面的依赖
 [target.'cfg(target_arch = "x86_64")'.dependencies]

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

@@ -28,7 +28,7 @@ use crate::{
 };
 
 use crate::mm::kernel_mapper::KernelMapper;
-use crate::mm::page::{EntryFlags, PageEntry, PAGE_1G_SHIFT};
+use crate::mm::page::{page_manager_lock_irqsave, EntryFlags, PageEntry, PAGE_1G_SHIFT};
 use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags};
 
 use system_error::SystemError;
@@ -734,7 +734,13 @@ 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() {
-            return allocator.allocate(count);
+            // 首次分配时内存不足
+            allocator.allocate(count).or_else(|| {
+                let mut page_manager_guard = page_manager_lock_irqsave();
+                // 释放部分页面并再次尝试分配
+                page_manager_guard.shrink_list();
+                return allocator.allocate(count);
+            })
         } else {
             return None;
         }

+ 6 - 0
kernel/src/filesystem/vfs/file.rs

@@ -163,6 +163,12 @@ impl PageCache {
         page
     }
 
+    pub fn remove_page(&self, offset: usize) {
+        let mut guard = self.xarray.lock();
+        let mut cursor = guard.cursor_mut(offset as u64);
+        cursor.remove();
+    }
+
     // pub fn get_pages(&self, start_pgoff: usize, end_pgoff: usize) -> Vec<Arc<Page>> {
     //     let mut vec = Vec::new();
     //     for pgoff in start_pgoff..=end_pgoff {

+ 2 - 2
kernel/src/ipc/shm.rs

@@ -165,7 +165,7 @@ impl ShmManager {
         let mut page_manager_guard = page_manager_lock_irqsave();
         let mut cur_phys = PhysPageFrame::new(phys_page.0);
         for _ in 0..page_count.data() {
-            let page = Arc::new(Page::new(true, cur_phys));
+            let page = Arc::new(Page::new(true, cur_phys.phys_address()));
             page.write().set_shm_id(shm_id);
             let paddr = cur_phys.phys_address();
             page_manager_guard.insert(paddr, &page);
@@ -436,7 +436,7 @@ impl KernelShm {
 
     /// 共享内存段的映射计数(有多少个不同的VMA映射)
     pub fn map_count(&self) -> usize {
-        let page_manager_guard = page_manager_lock_irqsave();
+        let mut page_manager_guard = page_manager_lock_irqsave();
         let mut id_set: HashSet<usize> = HashSet::new();
         let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr);
         let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap();

+ 2 - 2
kernel/src/ipc/syscall.rs

@@ -371,7 +371,7 @@ impl Syscall {
                 vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
 
                 // 将该虚拟内存区域映射到共享内存区域
-                let page_manager_guard = page_manager_lock_irqsave();
+                let mut page_manager_guard = page_manager_lock_irqsave();
                 let mut virt = VirtPageFrame::new(vaddr);
                 for _ in 0..count.data() {
                     let r = unsafe {
@@ -441,7 +441,7 @@ impl Syscall {
             .0;
 
         // 如果物理页的shm_id为None,代表不是共享页
-        let page_manager_guard = page_manager_lock_irqsave();
+        let mut page_manager_guard = page_manager_lock_irqsave();
         let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?;
         let shm_id = page.read().shm_id().ok_or(SystemError::EINVAL)?;
         drop(page_manager_guard);

+ 26 - 11
kernel/src/mm/fault.rs

@@ -21,7 +21,7 @@ use crate::{
 use crate::mm::MemoryManagementArch;
 
 use super::{
-    allocator::page_frame::{FrameAllocator, PhysPageFrame},
+    allocator::page_frame::FrameAllocator,
     page::{Page, PageFlags},
 };
 
@@ -258,8 +258,8 @@ impl PageFaultHandler {
                 klog_types::LogSource::Buddy,
             );
             let paddr = mapper.translate(address).unwrap().0;
-            let anon_vma_guard = page_manager_lock_irqsave();
-            let page = anon_vma_guard.get_unwrap(&paddr);
+            let mut page_manager_guard = page_manager_lock_irqsave();
+            let page = page_manager_guard.get_unwrap(&paddr);
             page.write().insert_vma(vma.clone());
             VmFaultReason::VM_FAULT_COMPLETED
         } else {
@@ -433,7 +433,7 @@ impl PageFaultHandler {
         let address = pfm.address_aligned_down();
         let vma = pfm.vma.clone();
         let old_paddr = mapper.translate(address).unwrap().0;
-        let page_manager = page_manager_lock_irqsave();
+        let mut page_manager = page_manager_lock_irqsave();
         let map_count = page_manager.get_unwrap(&old_paddr).read().map_count();
         drop(page_manager);
 
@@ -447,15 +447,15 @@ impl PageFaultHandler {
             table.set_entry(i, entry);
             VmFaultReason::VM_FAULT_COMPLETED
         } else if let Some(flush) = mapper.map(address, new_flags) {
-            let page_manager = page_manager_lock_irqsave();
-            let old_page = page_manager.get_unwrap(&old_paddr);
+            let mut page_manager_guard = page_manager_lock_irqsave();
+            let old_page = page_manager_guard.get_unwrap(&old_paddr);
             old_page.write().remove_vma(&vma);
-            drop(page_manager);
+            // drop(page_manager_guard);
 
             flush.flush();
             let paddr = mapper.translate(address).unwrap().0;
-            let anon_vma_guard = page_manager_lock_irqsave();
-            let page = anon_vma_guard.get_unwrap(&paddr);
+            // let mut page_manager_guard = page_manager_lock_irqsave();
+            let page = page_manager_guard.get_unwrap(&paddr);
             page.write().insert_vma(vma.clone());
 
             (MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
@@ -630,12 +630,15 @@ impl PageFaultHandler {
             (MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8)
                 .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
 
-            let page = Arc::new(Page::new(false, PhysPageFrame::new(new_cache_page)));
+            let page = Arc::new(Page::new(false, new_cache_page));
             pfm.page = Some(page.clone());
 
             page_manager_guard.insert(new_cache_page, &page);
             page_cache.add_page(file_pgoff, &page);
 
+            page.write()
+                .set_page_cache_index(Some(page_cache), Some(file_pgoff));
+
             //     // 分配空白页并映射到缺页地址
             //     mapper.map(pfm.address, vma_guard.flags()).unwrap().flush();
             //     let new_frame = phys_2_virt(mapper.translate(pfm.address).unwrap().0.data());
@@ -667,11 +670,23 @@ impl PageFaultHandler {
                 .flush();
 
             //复制PageCache内容到新的页内
-            let new_frame = MMArch::phys_2_virt(mapper.translate(pfm.address).unwrap().0).unwrap();
+            let new_phys = mapper.translate(pfm.address).unwrap().0;
+            let new_frame = MMArch::phys_2_virt(new_phys).unwrap();
             (new_frame.data() as *mut u8).copy_from_nonoverlapping(
                 MMArch::phys_2_virt(page_phys).unwrap().data() as *mut u8,
                 MMArch::PAGE_SIZE,
             );
+
+            let vma = pfm.vma();
+            let vma_guard = vma.lock();
+            let file = vma_guard.vm_file().expect("no vm_file in vma");
+            let page_cache = file.inode().page_cache().unwrap();
+            let page_guard = cache_page.read();
+            let new_page = Arc::new(Page::new(page_guard.shared(), new_phys));
+            page_cache.add_page(pfm.file_pgoff.unwrap(), &new_page);
+            new_page
+                .write()
+                .set_page_cache_index(cache_page.read().page_cache(), cache_page.read().index());
         } else {
             // 直接映射到PageCache
             mapper.map_phys(*pfm.address(), page_phys, vma_guard.flags());

+ 79 - 33
kernel/src/mm/page.rs

@@ -7,12 +7,14 @@ use core::{
 };
 
 use alloc::sync::Arc;
-use hashbrown::{HashMap, HashSet};
+use hashbrown::HashSet;
 use log::{error, info};
+use lru::LruCache;
 
 use crate::{
     arch::{interrupt::ipi::send_ipi, MMArch},
     exception::ipi::{IpiKind, IpiTarget},
+    filesystem::vfs::file::PageCache,
     ipc::shm::ShmId,
     libs::{
         rwlock::RwLock,
@@ -21,7 +23,7 @@ use crate::{
 };
 
 use super::{
-    allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame},
+    allocator::page_frame::{FrameAllocator, PageFrameCount},
     syscall::ProtFlags,
     ucontext::LockedVMA,
     MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
@@ -56,44 +58,56 @@ pub fn page_manager_lock_irqsave() -> SpinLockGuard<'static, PageManager> {
 
 // 物理页管理器
 pub struct PageManager {
-    phys2page: HashMap<PhysAddr, Arc<Page>>,
+    phys2page: LruCache<PhysAddr, Arc<Page>>,
 }
 
 impl PageManager {
     pub fn new() -> Self {
         Self {
-            phys2page: HashMap::new(),
+            phys2page: LruCache::unbounded(),
         }
     }
 
     pub fn contains(&self, paddr: &PhysAddr) -> bool {
-        self.phys2page.contains_key(paddr)
+        self.phys2page.peek(paddr).is_some()
     }
 
-    pub fn get(&self, paddr: &PhysAddr) -> Option<Arc<Page>> {
+    pub fn get(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
         self.phys2page.get(paddr).cloned()
     }
 
-    pub fn get_unwrap(&self, paddr: &PhysAddr) -> Arc<Page> {
+    pub fn get_unwrap(&mut self, paddr: &PhysAddr) -> Arc<Page> {
         self.phys2page
             .get(paddr)
             .unwrap_or_else(|| panic!("Phys Page not found, {:?}", paddr))
             .clone()
     }
 
-    // pub fn get_mut(&mut self, paddr: &PhysAddr) -> RwLockWriteGuard<Page> {
-    //     self.phys2page
-    //         .get_mut(paddr)
-    //         .unwrap_or_else(|| panic!("{:?}", paddr))
-    //         .write()
-    // }
-
     pub fn insert(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
-        self.phys2page.insert(paddr, page.clone());
+        self.phys2page.put(paddr, page.clone());
     }
 
     pub fn remove_page(&mut self, paddr: &PhysAddr) {
-        self.phys2page.remove(paddr);
+        self.phys2page.pop(paddr);
+    }
+
+    pub fn shrink_list(&mut self) {
+        let entry = self.phys2page.peek_lru().unwrap();
+        let page = entry.1.clone();
+        let phys = *entry.0;
+        let page_cache = page.read().page_cache().unwrap();
+        for vma in page.read().anon_vma() {
+            let address_space = vma.lock().address_space().unwrap();
+            let address_space = address_space.upgrade().unwrap();
+            let mut guard = address_space.write();
+            let mapper = &mut guard.user_mapper.utable;
+            let virt = vma.lock().page_address(&page).unwrap();
+            unsafe {
+                mapper.unmap(virt, false).unwrap().flush();
+            }
+        }
+        self.phys2page.pop(&phys);
+        page_cache.remove_page(page.read().index().unwrap());
     }
 }
 
@@ -138,8 +152,8 @@ impl core::ops::DerefMut for Page {
 }
 
 impl Page {
-    pub fn new(shared: bool, phys_frame: PhysPageFrame) -> Self {
-        let inner = InnerPage::new(shared, phys_frame);
+    pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
+        let inner = InnerPage::new(shared, phys_addr);
         Self {
             inner: RwLock::new(inner),
         }
@@ -162,11 +176,14 @@ pub struct InnerPage {
     /// 标志
     flags: PageFlags,
     /// 页所在的物理页帧号
-    phys_frame: PhysPageFrame,
+    phys_addr: PhysAddr,
+    /// 在pagecache中的偏移
+    index: Option<usize>,
+    page_cache: Option<Arc<PageCache>>,
 }
 
 impl InnerPage {
-    pub fn new(shared: bool, phys_frame: PhysPageFrame) -> Self {
+    pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
         let dealloc_when_zero = !shared;
         Self {
             map_count: 0,
@@ -175,7 +192,9 @@ impl InnerPage {
             shm_id: None,
             anon_vma: HashSet::new(),
             flags: PageFlags::empty(),
-            phys_frame,
+            phys_addr,
+            index: None,
+            page_cache: None,
         }
     }
 
@@ -204,6 +223,31 @@ impl InnerPage {
         self.shm_id
     }
 
+    pub fn index(&self) -> Option<usize> {
+        self.index
+    }
+
+    pub fn page_cache(&self) -> Option<Arc<PageCache>> {
+        self.page_cache.clone()
+    }
+
+    pub fn set_page_cache(&mut self, page_cache: Option<Arc<PageCache>>) {
+        self.page_cache = page_cache;
+    }
+
+    pub fn set_index(&mut self, index: Option<usize>) {
+        self.index = index;
+    }
+
+    pub fn set_page_cache_index(
+        &mut self,
+        page_cache: Option<Arc<PageCache>>,
+        index: Option<usize>,
+    ) {
+        self.page_cache = page_cache;
+        self.index = index;
+    }
+
     pub fn set_shm_id(&mut self, shm_id: ShmId) {
         self.shm_id = Some(shm_id);
     }
@@ -227,14 +271,9 @@ impl InnerPage {
         &self.flags
     }
 
-    #[inline(always)]
-    pub fn phys_frame(&self) -> &PhysPageFrame {
-        &self.phys_frame
-    }
-
     #[inline(always)]
     pub fn phys_address(&self) -> PhysAddr {
-        self.phys_frame.phys_address()
+        self.phys_addr
     }
 }
 
@@ -411,11 +450,18 @@ impl<Arch: MemoryManagementArch> PageTable<Arch> {
                             new_table.set_entry(i, entry);
                         } else {
                             let phys = allocator.allocate_one()?;
-                            let mut anon_vma_guard = page_manager_lock_irqsave();
-                            anon_vma_guard.insert(
-                                phys,
-                                &Arc::new(Page::new(false, PhysPageFrame::new(phys))),
-                            );
+                            let mut page_manager_guard = page_manager_lock_irqsave();
+                            let old_phys = entry.address().unwrap();
+                            let old_page = page_manager_guard.get_unwrap(&old_phys);
+                            let new_page = Arc::new(Page::new(old_page.read().shared(), phys));
+                            if let Some(ref page_cache) = old_page.read().page_cache() {
+                                new_page.write().set_page_cache_index(
+                                    Some(page_cache.clone()),
+                                    old_page.read().index(),
+                                );
+                            }
+
+                            page_manager_guard.insert(phys, &new_page);
                             let old_phys = entry.address().unwrap();
                             let frame = MMArch::phys_2_virt(phys).unwrap().data() as *mut u8;
                             frame.copy_from_nonoverlapping(
@@ -961,7 +1007,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
         let mut page_manager_guard: SpinLockGuard<'static, PageManager> =
             page_manager_lock_irqsave();
         if !page_manager_guard.contains(&phys) {
-            page_manager_guard.insert(phys, &Arc::new(Page::new(false, PhysPageFrame::new(phys))))
+            page_manager_guard.insert(phys, &Arc::new(Page::new(false, phys)))
         }
 
         return self.map_phys(virt, phys, flags);

+ 24 - 7
kernel/src/mm/ucontext.rs

@@ -35,7 +35,7 @@ use super::{
     allocator::page_frame::{
         deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter,
     },
-    page::{EntryFlags, Flusher, InactiveFlusher, PageFlushAll},
+    page::{EntryFlags, Flusher, InactiveFlusher, Page, PageFlushAll},
     syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags},
     MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags,
 };
@@ -187,15 +187,15 @@ impl InnerAddressSpace {
             // debug!("new vma: {:x?}", new_vma);
             let new_vma_guard = new_vma.lock();
             let new_mapper = &new_guard.user_mapper.utable;
-            let anon_vma_guard = page_manager_lock_irqsave();
+            let mut page_manager_guard = page_manager_lock_irqsave();
             for page in new_vma_guard.pages().map(|p| p.virt_address()) {
                 if let Some((paddr, _)) = new_mapper.translate(page) {
-                    let page = anon_vma_guard.get_unwrap(&paddr);
+                    let page = page_manager_guard.get_unwrap(&paddr);
                     page.write().insert_vma(new_vma.clone());
                 }
             }
 
-            drop(anon_vma_guard);
+            drop(page_manager_guard);
             drop(vma_guard);
             drop(new_vma_guard);
         }
@@ -1251,7 +1251,7 @@ impl LockedVMA {
         });
 
         // 重新设置before、after这两个VMA里面的物理页的anon_vma
-        let page_manager_guard = page_manager_lock_irqsave();
+        let mut page_manager_guard = page_manager_lock_irqsave();
         if let Some(before) = before.clone() {
             let virt_iter = before.lock().region.iter_pages();
             for frame in virt_iter {
@@ -1419,6 +1419,10 @@ impl VMA {
         return self.vm_file.clone();
     }
 
+    pub fn address_space(&self) -> Option<Weak<AddressSpace>> {
+        return self.user_address_space.clone();
+    }
+
     pub fn set_vm_flags(&mut self, vm_flags: VmFlags) {
         self.vm_flags = vm_flags;
     }
@@ -1572,7 +1576,7 @@ impl VMA {
         ));
 
         // 将VMA加入到anon_vma中
-        let page_manager_guard = page_manager_lock_irqsave();
+        let mut page_manager_guard = page_manager_lock_irqsave();
         cur_phy = phys;
         for _ in 0..count.data() {
             let paddr = cur_phy.phys_address();
@@ -1642,7 +1646,7 @@ impl VMA {
         // debug!("VMA::zeroed: flusher dropped");
 
         // 清空这些内存并将VMA加入到anon_vma中
-        let page_manager_guard = page_manager_lock_irqsave();
+        let mut page_manager_guard = page_manager_lock_irqsave();
         let virt_iter: VirtPageFrameIter =
             VirtPageFrameIter::new(destination, destination.add(page_count));
         for frame in virt_iter {
@@ -1655,6 +1659,19 @@ impl VMA {
         // debug!("VMA::zeroed: done");
         return Ok(r);
     }
+
+    pub fn page_address(&self, page: &Arc<Page>) -> Result<VirtAddr, SystemError> {
+        let page_guard = page.read();
+        let index = page_guard.index().unwrap();
+        if index >= self.file_pgoff.unwrap() {
+            let address =
+                self.region.start + ((index - self.file_pgoff.unwrap()) << MMArch::PAGE_SHIFT);
+            if address <= self.region.end() {
+                return Ok(address);
+            }
+        }
+        return Err(SystemError::EFAULT);
+    }
 }
 
 impl Drop for VMA {