still buggy, maybe concurrency
This commit is contained in:
parent
a4ef3e1a5a
commit
a42c008e12
@ -63,6 +63,8 @@ void ramdiskrw(struct buf*);
|
|||||||
void* kalloc(void);
|
void* kalloc(void);
|
||||||
void kfree(void *);
|
void kfree(void *);
|
||||||
void kinit(void);
|
void kinit(void);
|
||||||
|
void refcount_add(uint64 pa, int val);
|
||||||
|
int refcount_get(uint64 pa);
|
||||||
|
|
||||||
// log.c
|
// log.c
|
||||||
void initlog(int, struct superblock*);
|
void initlog(int, struct superblock*);
|
||||||
|
|||||||
@ -13,6 +13,7 @@ void freerange(void *pa_start, void *pa_end);
|
|||||||
|
|
||||||
extern char end[]; // first address after kernel.
|
extern char end[]; // first address after kernel.
|
||||||
// defined by kernel.ld.
|
// defined by kernel.ld.
|
||||||
|
int refcount[(PHYSTOP - KERNBASE) >> PGSHIFT];
|
||||||
|
|
||||||
struct run {
|
struct run {
|
||||||
struct run *next;
|
struct run *next;
|
||||||
@ -27,17 +28,38 @@ void
|
|||||||
kinit()
|
kinit()
|
||||||
{
|
{
|
||||||
initlock(&kmem.lock, "kmem");
|
initlock(&kmem.lock, "kmem");
|
||||||
|
memset(refcount, 0, sizeof(refcount));
|
||||||
freerange(end, (void*)PHYSTOP);
|
freerange(end, (void*)PHYSTOP);
|
||||||
}
|
}
|
||||||
|
int total_free;
|
||||||
|
int alloc_count;
|
||||||
|
int free_count;
|
||||||
|
int count_ref() {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < NELEM(refcount); ++ i) {
|
||||||
|
count += (refcount[i] > 0);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_page_count()
|
||||||
|
{
|
||||||
|
int ref_count = count_ref();
|
||||||
|
printf("count ref: %d / %d; alloc=%d, free=%d\n", ref_count, total_free, alloc_count, free_count);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
freerange(void *pa_start, void *pa_end)
|
freerange(void *pa_start, void *pa_end)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
total_free = alloc_count = free_count = 0;
|
||||||
p = (char*)PGROUNDUP((uint64)pa_start);
|
p = (char*)PGROUNDUP((uint64)pa_start);
|
||||||
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE, total_free ++){
|
||||||
|
refcount_add((uint64)p, 1);
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
|
show_page_count();
|
||||||
|
}
|
||||||
|
|
||||||
// Free the page of physical memory pointed at by pa,
|
// Free the page of physical memory pointed at by pa,
|
||||||
// which normally should have been returned by a
|
// which normally should have been returned by a
|
||||||
@ -51,12 +73,29 @@ kfree(void *pa)
|
|||||||
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
||||||
panic("kfree");
|
panic("kfree");
|
||||||
|
|
||||||
|
//* [COW] if still has refcount after dec, keep it
|
||||||
|
refcount_add((uint64)pa, -1);
|
||||||
|
free_count++;
|
||||||
|
acquire(&kmem.lock);
|
||||||
|
if (refcount_get((uint64)pa) > 0) {
|
||||||
|
release(&kmem.lock);
|
||||||
|
return;
|
||||||
|
} else if (refcount_get((uint64)pa) < 0) {
|
||||||
|
panic("kfree: invalid refcount");
|
||||||
|
}
|
||||||
|
refcount[((uint64)pa - KERNBASE) >> PGSHIFT] = 0;
|
||||||
|
release(&kmem.lock);
|
||||||
|
|
||||||
// Fill with junk to catch dangling refs.
|
// Fill with junk to catch dangling refs.
|
||||||
memset(pa, 1, PGSIZE);
|
memset(pa, 1, PGSIZE);
|
||||||
|
|
||||||
r = (struct run*)pa;
|
r = (struct run*)pa;
|
||||||
|
|
||||||
acquire(&kmem.lock);
|
acquire(&kmem.lock);
|
||||||
|
if (alloc_count) {
|
||||||
|
if (r == 0) panic("kfree r");
|
||||||
|
if (kmem.freelist == 0) panic("kfree");
|
||||||
|
}
|
||||||
r->next = kmem.freelist;
|
r->next = kmem.freelist;
|
||||||
kmem.freelist = r;
|
kmem.freelist = r;
|
||||||
release(&kmem.lock);
|
release(&kmem.lock);
|
||||||
@ -72,11 +111,36 @@ kalloc(void)
|
|||||||
|
|
||||||
acquire(&kmem.lock);
|
acquire(&kmem.lock);
|
||||||
r = kmem.freelist;
|
r = kmem.freelist;
|
||||||
if(r)
|
if(r) {
|
||||||
kmem.freelist = r->next;
|
kmem.freelist = r->next;
|
||||||
|
int idx = ((uint64)r - KERNBASE) >> PGSHIFT;
|
||||||
|
if (idx < 0 || idx >= NELEM(refcount)) panic("!!!");
|
||||||
|
refcount[idx] = 1;
|
||||||
|
alloc_count ++;
|
||||||
|
} else {
|
||||||
|
show_page_count();
|
||||||
|
}
|
||||||
release(&kmem.lock);
|
release(&kmem.lock);
|
||||||
|
|
||||||
if(r)
|
if(r)
|
||||||
memset((char*)r, 5, PGSIZE); // fill with junk
|
memset((char*)r, 5, PGSIZE); // fill with junk
|
||||||
return (void*)r;
|
return (void*)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
refcount_add(uint64 pa, int val)
|
||||||
|
{
|
||||||
|
acquire(&kmem.lock);
|
||||||
|
int idx = (pa - KERNBASE) >> PGSHIFT;
|
||||||
|
if (idx < 0 || idx >= NELEM(refcount)) panic("!!!");
|
||||||
|
refcount[idx] += val;
|
||||||
|
release(&kmem.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
refcount_get(uint64 pa)
|
||||||
|
{
|
||||||
|
int idx = (pa - KERNBASE) >> PGSHIFT;
|
||||||
|
if (idx < 0 || idx >= NELEM(refcount)) panic("!!!");
|
||||||
|
return refcount[idx];
|
||||||
|
}
|
||||||
@ -321,7 +321,8 @@ fork(void)
|
|||||||
acquire(&np->lock);
|
acquire(&np->lock);
|
||||||
np->state = RUNNABLE;
|
np->state = RUNNABLE;
|
||||||
release(&np->lock);
|
release(&np->lock);
|
||||||
|
extern void show_page_count();
|
||||||
|
show_page_count();
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -344,6 +344,8 @@ typedef uint64 *pagetable_t; // 512 PTEs
|
|||||||
#define PTE_X (1L << 3)
|
#define PTE_X (1L << 3)
|
||||||
#define PTE_U (1L << 4) // user can access
|
#define PTE_U (1L << 4) // user can access
|
||||||
|
|
||||||
|
#define PTE_COW (1L << 8) // use RSW bit 8 as COW flag
|
||||||
|
|
||||||
// shift a physical address to the right place for a PTE.
|
// shift a physical address to the right place for a PTE.
|
||||||
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
|
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,37 @@ usertrap(void)
|
|||||||
intr_on();
|
intr_on();
|
||||||
|
|
||||||
syscall();
|
syscall();
|
||||||
|
} else if(r_scause() == 15){
|
||||||
|
// Store/AMO page fault
|
||||||
|
uint64 stval = r_stval();
|
||||||
|
pte_t* pte = walk(p->pagetable, stval, 0);
|
||||||
|
uint64 pa0 = PTE2PA((*pte));
|
||||||
|
if ((*pte & PTE_COW) && !(*pte & PTE_W)) {
|
||||||
|
// printf("COW: sepc=%p, stval=%p, pte=%p\n", r_sepc(), r_stval(), *pte);
|
||||||
|
if (refcount_get(pa0) > 1) {
|
||||||
|
uint64 newpage = (uint64)kalloc();
|
||||||
|
if (newpage == 0) {
|
||||||
|
printf("killed due to no mem\n");
|
||||||
|
setkilled(p);
|
||||||
|
} else {
|
||||||
|
pte_t save_pte = * pte;
|
||||||
|
memmove((void*)newpage, (void*)pa0, PGSIZE);
|
||||||
|
uvmunmap(p->pagetable, PGROUNDDOWN(stval), 1, 0);
|
||||||
|
refcount_add(pa0, -1);
|
||||||
|
mappages(p->pagetable, PGROUNDDOWN(stval), PGSIZE, newpage,
|
||||||
|
(PTE_FLAGS(save_pte) | PTE_W) & (~PTE_COW));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//* [COW] this pa is no more shared
|
||||||
|
*pte |= PTE_W;
|
||||||
|
*pte &= ~PTE_COW;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Store/AMO page fault\n");
|
||||||
|
printf(" pid=%d PTE=%p\n", p->pid, *pte);
|
||||||
|
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||||
|
setkilled(p);
|
||||||
|
}
|
||||||
} else if((which_dev = devintr()) != 0){
|
} else if((which_dev = devintr()) != 0){
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
43
kernel/vm.c
43
kernel/vm.c
@ -308,7 +308,7 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
|||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
uint64 pa, i;
|
uint64 pa, i;
|
||||||
uint flags;
|
uint flags;
|
||||||
char *mem;
|
// char *mem;
|
||||||
|
|
||||||
for(i = 0; i < sz; i += PGSIZE){
|
for(i = 0; i < sz; i += PGSIZE){
|
||||||
if((pte = walk(old, i, 0)) == 0)
|
if((pte = walk(old, i, 0)) == 0)
|
||||||
@ -316,14 +316,23 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
|||||||
if((*pte & PTE_V) == 0)
|
if((*pte & PTE_V) == 0)
|
||||||
panic("uvmcopy: page not present");
|
panic("uvmcopy: page not present");
|
||||||
pa = PTE2PA(*pte);
|
pa = PTE2PA(*pte);
|
||||||
|
if (*pte & PTE_W) {
|
||||||
|
//* [COW] let go those read-only pages
|
||||||
|
*pte &= ~PTE_W;
|
||||||
|
*pte |= PTE_COW;
|
||||||
|
}
|
||||||
|
//* [COW] clear parent's PTE_W, and 'll be carried to child's pgtbl
|
||||||
flags = PTE_FLAGS(*pte);
|
flags = PTE_FLAGS(*pte);
|
||||||
if((mem = kalloc()) == 0)
|
// *[COW] no alloc and copy here
|
||||||
goto err;
|
// if((mem = kalloc()) == 0)
|
||||||
memmove(mem, (char*)pa, PGSIZE);
|
// goto err;
|
||||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
// memmove(mem, (char*)pa, PGSIZE);
|
||||||
kfree(mem);
|
// if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||||
|
if(mappages(new, i, PGSIZE, pa, flags) != 0){
|
||||||
|
// kfree(mem);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
refcount_add(pa, 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -361,6 +370,28 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
|||||||
n = PGSIZE - (dstva - va0);
|
n = PGSIZE - (dstva - va0);
|
||||||
if(n > len)
|
if(n > len)
|
||||||
n = len;
|
n = len;
|
||||||
|
pte_t* pte = walk(pagetable, va0, 0);
|
||||||
|
if ((*pte & PTE_COW) && !(*pte & PTE_W)) {
|
||||||
|
if (refcount_get(PTE2PA(*pte)) > 1) {
|
||||||
|
uint64 newpage = (uint64)kalloc();
|
||||||
|
if (newpage == 0) {
|
||||||
|
printf("killed due to no mem in copyout\n");
|
||||||
|
setkilled(myproc());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
pte_t save_pte = *pte;
|
||||||
|
memmove((void*)newpage, (void*)pa0, PGSIZE);
|
||||||
|
uvmunmap(pagetable, PGROUNDDOWN(va0), 1, 0);
|
||||||
|
refcount_add(pa0, -1);
|
||||||
|
mappages(pagetable, PGROUNDDOWN(va0), PGSIZE, newpage,
|
||||||
|
(PTE_FLAGS(save_pte) | PTE_W) & (~PTE_COW));
|
||||||
|
pa0 = newpage;
|
||||||
|
} else {
|
||||||
|
//* [COW] this pa is no more shared
|
||||||
|
*pte |= PTE_W;
|
||||||
|
*pte &= ~PTE_COW;
|
||||||
|
}
|
||||||
|
}
|
||||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||||
|
|
||||||
len -= n;
|
len -= n;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user