cowtest passed
This commit is contained in:
123
kernel/vm.c
123
kernel/vm.c
@@ -5,6 +5,8 @@
|
||||
#include "riscv.h"
|
||||
#include "defs.h"
|
||||
#include "fs.h"
|
||||
#include "proc.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
/*
|
||||
* the kernel's page table.
|
||||
@@ -309,13 +311,14 @@ uvmfree(pagetable_t pagetable, uint64 sz)
|
||||
// physical memory.
|
||||
// returns 0 on success, -1 on failure.
|
||||
// frees any allocated pages on failure.
|
||||
// 如果父进程的一个 PTE 本身就是不可写的,则没有必要PTE_COW
|
||||
// 因为子进程对这块物理页也一定是不可写的,那么就没必要复制,因此只有当父进程的 PTE_W 标记时,才去附加 PTE_COW。
|
||||
int
|
||||
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
{
|
||||
pte_t *pte;
|
||||
uint64 pa, i;
|
||||
uint flags;
|
||||
char *mem;
|
||||
|
||||
for(i = 0; i < sz; i += PGSIZE){
|
||||
if((pte = walk(old, i, 0)) == 0)
|
||||
@@ -323,14 +326,20 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
if((*pte & PTE_V) == 0)
|
||||
panic("uvmcopy: page not present");
|
||||
pa = PTE2PA(*pte);
|
||||
|
||||
// lab5: Copy on write
|
||||
// father
|
||||
// 如果该页本身就不可写,那么子进程肯定也不可写,不用对其考虑COW
|
||||
if(*pte & PTE_W){
|
||||
*pte &= ~PTE_W;
|
||||
*pte |= PTE_COW;
|
||||
}
|
||||
flags = PTE_FLAGS(*pte);
|
||||
if((mem = kalloc()) == 0)
|
||||
goto err;
|
||||
memmove(mem, (char*)pa, PGSIZE);
|
||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||
kfree(mem);
|
||||
// child
|
||||
if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){
|
||||
goto err;
|
||||
}
|
||||
reference_operation((void*)pa, PLUS);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -338,7 +347,6 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// mark a PTE invalid for user access.
|
||||
// used by exec for the user stack guard page.
|
||||
void
|
||||
@@ -352,35 +360,6 @@ uvmclear(pagetable_t pagetable, uint64 va)
|
||||
*pte &= ~PTE_U;
|
||||
}
|
||||
|
||||
// Copy from kernel to user.
|
||||
// Copy len bytes from src to virtual address dstva in a given page table.
|
||||
// Return 0 on success, -1 on error.
|
||||
int
|
||||
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
pte_t *pte;
|
||||
|
||||
while(len > 0){
|
||||
va0 = PGROUNDDOWN(dstva);
|
||||
if(va0 >= MAXVA)
|
||||
return -1;
|
||||
pte = walk(pagetable, va0, 0);
|
||||
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||
|
||||
(*pte & PTE_W) == 0)
|
||||
return -1;
|
||||
pa0 = PTE2PA(*pte);
|
||||
n = PGSIZE - (dstva - va0);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||
|
||||
len -= n;
|
||||
src += n;
|
||||
dstva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy from user to kernel.
|
||||
// Copy len bytes to dst from virtual address srcva in a given page table.
|
||||
@@ -449,3 +428,75 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否为cowpage
|
||||
int
|
||||
iscowpage(uint64 va){
|
||||
struct proc* p = myproc();
|
||||
va = PGROUNDDOWN((uint64)va);
|
||||
if(va >= MAXVA) // 要在walk之前
|
||||
return 0;
|
||||
pte_t* pte = walk(p->pagetable,va,0);
|
||||
if(pte == 0)
|
||||
return 0;
|
||||
if((va < p->sz)&& (*pte & PTE_COW) && (*pte & PTE_V))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cow 的主要操作,将该 PTE 重新映射至新的物理内存,并修改flag
|
||||
void
|
||||
startcowcopy(uint64 va){
|
||||
struct proc* p = myproc();
|
||||
va = PGROUNDDOWN((uint64)va);
|
||||
pte_t* pte = walk(p->pagetable,va,0);
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
|
||||
void* new = cowcopy_pa((void*)pa);
|
||||
if((uint64)new == 0){
|
||||
panic("cowcopy_pa err\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
uint64 flags = (PTE_FLAGS(*pte) | PTE_W) & (~PTE_COW);
|
||||
// 确保PTE_U没有丢失
|
||||
if (!(flags & PTE_U)) flags |= PTE_U;
|
||||
uvmunmap(p->pagetable, va, 1, 0); // 不包含kfree,因为ref--在cowcopy_pa中已经进行了
|
||||
|
||||
if(mappages(p->pagetable, va, PGSIZE, (uint64)new, flags) == -1){
|
||||
kfree(new);
|
||||
panic("cow mappages failed");
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from kernel to user.
|
||||
// Copy len bytes from src to virtual address dstva in a given page table.
|
||||
// Return 0 on success, -1 on error.
|
||||
int
|
||||
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
|
||||
while(len > 0){
|
||||
va0 = PGROUNDDOWN(dstva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
|
||||
if(iscowpage(va0)){
|
||||
startcowcopy(va0);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
}
|
||||
|
||||
n = PGSIZE - (dstva - va0);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||
|
||||
len -= n;
|
||||
src += n;
|
||||
dstva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user