From e72643c379ae946295b8906c3994cd852de0e4ee Mon Sep 17 00:00:00 2001
From: Linermao <LinermaoGemail@gmail.com>
Date: Fri, 20 Dec 2024 14:49:40 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20copy=20on=20write=20?=
 =?UTF-8?q?=E6=9C=BA=E5=88=B6=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=B7=B2=E7=9F=A5?=
 =?UTF-8?q?=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 kernel/defs.h |  7 ++++++-
 kernel/trap.c | 14 ++++++++++++--
 kernel/vm.c   | 15 +++++++++++++--
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/kernel/defs.h b/kernel/defs.h
index b1656f7..e01e6db 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -3,6 +3,7 @@
 
 #include "types.h"
 #include "ipc_hash.h"
+#include "riscv.h"
 
 #define ASSERT(x, info)\
 do\
@@ -80,6 +81,10 @@ void            kfree(void *);
 void            kinit(void);
 void*           kbuddy_alloc(uint32);
 void            kbuddy_free(void *, uint32);
+int             kaddrefcnt(void*);
+void*           cowalloc(pagetable_t, uint64);
+int             krefcnt(void*);
+int             cowpage(pagetable_t, uint64); 
 
 // log.c
 void            initlog(int, struct superblock*);
@@ -94,7 +99,7 @@ int             piperead(struct pipe*, uint64, int);
 int             pipewrite(struct pipe*, uint64, int);
 
 // printf.c
-int            printf(char*, ...) __attribute__ ((format (printf, 1, 2)));
+int             printf(char*, ...) __attribute__ ((format (printf, 1, 2)));
 void            panic(char*) __attribute__((noreturn));
 void            printfinit(void);
 
diff --git a/kernel/trap.c b/kernel/trap.c
index 43ca6c5..e1420a4 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -72,9 +72,19 @@ usertrap(void)
   } else if(r_scause() == 13 || r_scause() == 15){ // 加载页面与保存页面错误
     uint64 va;
     va = r_stval();
-    if (uvlazyalloc(p->pagetable, va) < 0) {
+    pte_t* pte = walk(p->pagetable, va, 0);
+
+    if ((*pte & PTE_V) == 0){
+      if (uvlazyalloc(p->pagetable, va) < 0) {
+        setkilled(p);
+      } 
+    }else if (*pte & PTE_F){
+      if (va >= p->sz || cowpage(p->pagetable, va) != 0 || cowalloc(p->pagetable, PGROUNDDOWN(va)) == 0){
+        setkilled(p);
+      }
+    }else {
       setkilled(p);
-    } 
+    }
     
   } else {
     // 错误则kill这个进程
diff --git a/kernel/vm.c b/kernel/vm.c
index 084821c..87d1f69 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -256,10 +256,10 @@ int uvlazyalloc(pagetable_t pagetable, uint64 va){
   va = PGROUNDDOWN(va);
 
   if (va > myproc()->sz) {
-    printf("va is greater than sz");
+    printf("va is greater than sz\n");
     return -1;
   }else if (va < myproc()->ustack_top){
-    printf("va is less than ustack_top");
+    printf("va is less than ustack_top\n");
     return -1;
   }
 
@@ -374,8 +374,17 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
     if((*pte & PTE_V) == 0)
       // panic("uvmcopy: page not present");
       continue;
+
     pa = PTE2PA(*pte);
     flags = PTE_FLAGS(*pte);
+
+    // 仅对可写页面设置COW标记
+    if(flags & PTE_W) {
+      // 禁用写并设置COW Fork标记
+      flags = (flags | PTE_F) & ~PTE_W;
+      *pte = PA2PTE(pa) | flags;
+    }
+
     if((mem = kalloc()) == 0)
       goto err;
     memmove(mem, (char*)pa, PGSIZE);
@@ -383,6 +392,8 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
       kfree(mem);
       goto err;
     }
+    // 增加内存的引用计数
+    kaddrefcnt((char*)pa);
   }
   return 0;
 
-- 
GitLab