MemoryShore 10 місяців тому
батько
коміт
62ec0e0dbe
1 змінених файлів з 50 додано та 8 видалено
  1. 50 8
      kernel/src/mm/fault.rs

+ 50 - 8
kernel/src/mm/fault.rs

@@ -56,6 +56,8 @@ pub struct PageFaultMessage {
     flags: FaultFlags,
     /// 缺页的文件页在文件中的偏移量
     file_pgoff: Option<usize>,
+    /// 缺页对应PageCache中的文件页
+    page: Option<Arc<Page>>,
 }
 
 impl PageFaultMessage {
@@ -69,6 +71,7 @@ impl PageFaultMessage {
             address,
             flags,
             file_pgoff,
+            page: None,
         }
     }
 
@@ -104,6 +107,7 @@ impl Clone for PageFaultMessage {
             address: self.address,
             flags: self.flags,
             file_pgoff: self.file_pgoff,
+            page: None,
         }
     }
 }
@@ -333,11 +337,15 @@ impl PageFaultHandler {
 
         // TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault
         log::info!("do_read_fault");
-        let ret = Self::do_fault_around(pfm.clone(), mapper);
+        let mut ret = Self::do_fault_around(pfm.clone(), mapper);
         if !ret.is_empty() {
             return ret;
         }
-        return Self::filemap_fault(pfm.clone(), mapper);
+        ret = Self::filemap_fault(pfm.clone(), mapper);
+
+        ret = ret.union(Self::finish_fault(pfm, mapper));
+        
+        ret
     }
 
     /// 处理对共享文件映射区写入引起的缺页
@@ -551,13 +559,17 @@ impl PageFaultHandler {
         VmFaultReason::empty()
     }
 
-    pub unsafe fn filemap_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
+    pub unsafe fn filemap_fault(
+        mut pfm: PageFaultMessage,
+        mapper: &mut PageMapper,
+    ) -> VmFaultReason {
         log::info!("filemap_fault");
         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 file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
+        let mut ret = VmFaultReason::empty();
 
         if let Some(page) = page_cache.get_page(file_pgoff) {
             // TODO 异步从磁盘中预读页面进PageCache
@@ -573,6 +585,8 @@ impl PageFaultHandler {
             new_frame.copy_from_nonoverlapping(frame, MMArch::PAGE_SIZE);
         } else {
             // TODO 同步预读
+            //涉及磁盘IO,返回标志为VM_FAULT_MAJOR
+            ret = VmFaultReason::VM_FAULT_MAJOR;
             let mut buf: Vec<u8> = vec![0; MMArch::PAGE_SIZE];
             file.pread(
                 file_pgoff * MMArch::PAGE_SIZE,
@@ -586,15 +600,43 @@ impl PageFaultHandler {
             let new_cache_page = allocator.allocate_one().unwrap();
             (phys_2_virt(new_cache_page.data()) as *mut u8)
                 .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
-            page_cache.add_page(
-                file_pgoff,
-                Arc::new(Page::new(false, PhysPageFrame::new(new_cache_page))),
-            );
 
+            let page = Arc::new(Page::new(false, PhysPageFrame::new(new_cache_page)));
+
+            page_cache.add_page(file_pgoff, page.clone());
+
+            pfm.page = Some(page);
+
+            //     // 分配空白页并映射到缺页地址
+            //     mapper.map(pfm.address, vma_guard.flags()).unwrap().flush();
+            //     let new_frame = phys_2_virt(mapper.translate(pfm.address).unwrap().0.data());
+            //     (new_frame as *mut u8).copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
+        }
+        ret
+    }
+
+    pub unsafe fn finish_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
+        let vma = pfm.vma();
+        let vma_guard = vma.lock();
+        let page = pfm.page.clone().expect("no page in pfm");
+        let cache_frame = page.phys_frame().phys_address();
+
+        if pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE)
+            && !pfm.vma().lock().vm_flags().contains(VmFlags::VM_SHARED)
+        {
+            // 私有文件映射的写时复制场景
             // 分配空白页并映射到缺页地址
             mapper.map(pfm.address, vma_guard.flags()).unwrap().flush();
+
+            //复制PageCache内容到新的页内
             let new_frame = phys_2_virt(mapper.translate(pfm.address).unwrap().0.data());
-            (new_frame as *mut u8).copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
+            (new_frame as *mut u8).copy_from_nonoverlapping(
+                phys_2_virt(cache_frame.data()) as *mut u8,
+                MMArch::PAGE_SIZE,
+            );
+        } else {
+            // 直接映射到PageCache
+            mapper.map_phys(*pfm.address(), cache_frame, vma_guard.flags());
         }
         VmFaultReason::VM_FAULT_COMPLETED
     }