have fork() fail, not panic, if not enough phys mem
This commit is contained in:
parent
18e76a6c47
commit
abfe9999f4
1
Makefile
1
Makefile
|
@ -128,6 +128,7 @@ UPROGS=\
|
||||||
$U/_usertests\
|
$U/_usertests\
|
||||||
$U/_wc\
|
$U/_wc\
|
||||||
$U/_zombie\
|
$U/_zombie\
|
||||||
|
$U/_cow\
|
||||||
|
|
||||||
fs.img: mkfs/mkfs README $(UPROGS)
|
fs.img: mkfs/mkfs README $(UPROGS)
|
||||||
mkfs/mkfs fs.img README $(UPROGS)
|
mkfs/mkfs fs.img README $(UPROGS)
|
||||||
|
|
|
@ -185,7 +185,7 @@ pagetable_t uvmcreate(void);
|
||||||
void uvminit(pagetable_t, uchar *, uint);
|
void uvminit(pagetable_t, uchar *, uint);
|
||||||
uint64 uvmalloc(pagetable_t, uint64, uint64);
|
uint64 uvmalloc(pagetable_t, uint64, uint64);
|
||||||
uint64 uvmdealloc(pagetable_t, uint64, uint64);
|
uint64 uvmdealloc(pagetable_t, uint64, uint64);
|
||||||
void uvmcopy(pagetable_t, pagetable_t, uint64);
|
int uvmcopy(pagetable_t, pagetable_t, uint64);
|
||||||
void uvmfree(pagetable_t, uint64);
|
void uvmfree(pagetable_t, uint64);
|
||||||
void mappages(pagetable_t, uint64, uint64, uint64, int);
|
void mappages(pagetable_t, uint64, uint64, uint64, int);
|
||||||
void unmappages(pagetable_t, uint64, uint64, int);
|
void unmappages(pagetable_t, uint64, uint64, int);
|
||||||
|
|
|
@ -109,6 +109,28 @@ found:
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free a proc structure and the data hanging from it,
|
||||||
|
// including user pages.
|
||||||
|
// the proc lock must be held.
|
||||||
|
static void
|
||||||
|
freeproc(struct proc *p)
|
||||||
|
{
|
||||||
|
if(p->kstack)
|
||||||
|
kfree(p->kstack);
|
||||||
|
p->kstack = 0;
|
||||||
|
if(p->tf)
|
||||||
|
kfree((void*)p->tf);
|
||||||
|
p->tf = 0;
|
||||||
|
if(p->pagetable)
|
||||||
|
proc_freepagetable(p->pagetable, p->sz);
|
||||||
|
p->pagetable = 0;
|
||||||
|
p->pid = 0;
|
||||||
|
p->parent = 0;
|
||||||
|
p->name[0] = 0;
|
||||||
|
p->killed = 0;
|
||||||
|
p->state = UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a page table for a given process,
|
// Create a page table for a given process,
|
||||||
// with no users pages, but with trampoline pages.
|
// with no users pages, but with trampoline pages.
|
||||||
// Called both when creating a process, and
|
// Called both when creating a process, and
|
||||||
|
@ -145,7 +167,8 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
|
||||||
{
|
{
|
||||||
unmappages(pagetable, TRAMPOLINE, PGSIZE, 0);
|
unmappages(pagetable, TRAMPOLINE, PGSIZE, 0);
|
||||||
unmappages(pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0);
|
unmappages(pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0);
|
||||||
uvmfree(pagetable, sz);
|
if(sz > 0)
|
||||||
|
uvmfree(pagetable, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a user program that calls exec("/init")
|
// a user program that calls exec("/init")
|
||||||
|
@ -223,7 +246,10 @@ fork(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy user memory from parent to child.
|
// Copy user memory from parent to child.
|
||||||
uvmcopy(p->pagetable, np->pagetable, p->sz);
|
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
|
||||||
|
freeproc(np);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
np->sz = p->sz;
|
np->sz = p->sz;
|
||||||
|
|
||||||
np->parent = p;
|
np->parent = p;
|
||||||
|
@ -319,17 +345,7 @@ wait(void)
|
||||||
if(np->state == ZOMBIE){
|
if(np->state == ZOMBIE){
|
||||||
// Found one.
|
// Found one.
|
||||||
pid = np->pid;
|
pid = np->pid;
|
||||||
kfree(np->kstack);
|
freeproc(np);
|
||||||
np->kstack = 0;
|
|
||||||
kfree((void*)np->tf);
|
|
||||||
np->tf = 0;
|
|
||||||
proc_freepagetable(np->pagetable, np->sz);
|
|
||||||
np->pagetable = 0;
|
|
||||||
np->pid = 0;
|
|
||||||
np->parent = 0;
|
|
||||||
np->name[0] = 0;
|
|
||||||
np->killed = 0;
|
|
||||||
np->state = UNUSED;
|
|
||||||
release(&ptable.lock);
|
release(&ptable.lock);
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
11
kernel/vm.c
11
kernel/vm.c
|
@ -273,7 +273,9 @@ uvmfree(pagetable_t pagetable, uint64 sz)
|
||||||
// its memory into a child's page table.
|
// its memory into a child's page table.
|
||||||
// Copies both the page table and the
|
// Copies both the page table and the
|
||||||
// physical memory.
|
// physical memory.
|
||||||
void
|
// returns 0 on success, -1 on failure.
|
||||||
|
// frees any allocated pages on failure.
|
||||||
|
int
|
||||||
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||||
{
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
@ -289,10 +291,15 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||||
pa = PTE2PA(*pte);
|
pa = PTE2PA(*pte);
|
||||||
flags = PTE_FLAGS(*pte);
|
flags = PTE_FLAGS(*pte);
|
||||||
if((mem = kalloc()) == 0)
|
if((mem = kalloc()) == 0)
|
||||||
panic("uvmcopy: kalloc failed");
|
goto err;
|
||||||
memmove(mem, (char*)pa, PGSIZE);
|
memmove(mem, (char*)pa, PGSIZE);
|
||||||
mappages(new, i, PGSIZE, (uint64)mem, flags);
|
mappages(new, i, PGSIZE, (uint64)mem, flags);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
unmappages(new, 0, i, 1);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy from kernel to user.
|
// Copy from kernel to user.
|
||||||
|
|
54
user/cow.c
Normal file
54
user/cow.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
//
|
||||||
|
// tests for copy-on-write fork() assignment.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/memlayout.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
// allocate more than half of physical memory,
|
||||||
|
// then fork. this will fail in the default
|
||||||
|
// kernel, which does not support copy-on-write.
|
||||||
|
void
|
||||||
|
simpletest()
|
||||||
|
{
|
||||||
|
uint64 phys_size = PHYSTOP - KERNBASE;
|
||||||
|
int sz = (phys_size / 3) * 2;
|
||||||
|
|
||||||
|
printf(1, "simple: ");
|
||||||
|
|
||||||
|
char *p = sbrk(sz);
|
||||||
|
if(p == (char*)0xffffffffffffffffL){
|
||||||
|
printf(1, "sbrk(%d) failed\n", sz);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(char *q = p; q < p + sz; q += 4096){
|
||||||
|
*(int*)q = getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf(1, "fork() failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pid == 0)
|
||||||
|
exit();
|
||||||
|
|
||||||
|
wait();
|
||||||
|
|
||||||
|
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
|
||||||
|
printf(1, "sbrk(-%d) failed\n", sz);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(1, "simple ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
simpletest();
|
||||||
|
exit();
|
||||||
|
}
|
Loading…
Reference in a new issue