modify uvmunmap() to be in aligned pages

fix a bug in fork() recovering from out of memory
This commit is contained in:
Robert Morris 2020-08-13 08:46:28 -04:00
parent e1a2cd59fa
commit 70c6fe861e
2 changed files with 18 additions and 21 deletions

View file

@ -175,8 +175,8 @@ proc_pagetable(struct proc *p)
void void
proc_freepagetable(pagetable_t pagetable, uint64 sz) proc_freepagetable(pagetable_t pagetable, uint64 sz)
{ {
uvmunmap(pagetable, TRAMPOLINE, PGSIZE, 0); uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmunmap(pagetable, TRAPFRAME, PGSIZE, 0); uvmunmap(pagetable, TRAPFRAME, 1, 0);
uvmfree(pagetable, sz); uvmfree(pagetable, sz);
} }

View file

@ -167,24 +167,23 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
return 0; return 0;
} }
// Remove mappings from a page table. The mappings in // Remove npages of mappings starting from va. va must be
// the given range must exist. Optionally free the // page-aligned. The mappings must exist.
// physical memory. // Optionally free the physical memory.
void void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free) uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{ {
uint64 a, last; uint64 a;
pte_t *pte; pte_t *pte;
a = PGROUNDDOWN(va); if((va % PGSIZE) != 0)
last = PGROUNDDOWN(va + size - 1); panic("uvmunmap: not aligned");
for(;;){
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0) if((pte = walk(pagetable, a, 0)) == 0)
panic("uvmunmap: walk"); panic("uvmunmap: walk");
if((*pte & PTE_V) == 0){ if((*pte & PTE_V) == 0)
printf("va=%p pte=%p\n", a, *pte);
panic("uvmunmap: not mapped"); panic("uvmunmap: not mapped");
}
if(PTE_FLAGS(*pte) == PTE_V) if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf"); panic("uvmunmap: not a leaf");
if(do_free){ if(do_free){
@ -192,9 +191,6 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free)
kfree((void*)pa); kfree((void*)pa);
} }
*pte = 0; *pte = 0;
if(a == last)
break;
a += PGSIZE;
} }
} }
@ -265,9 +261,10 @@ uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
if(newsz >= oldsz) if(newsz >= oldsz)
return oldsz; return oldsz;
uint64 newup = PGROUNDUP(newsz); if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
if(newup < PGROUNDUP(oldsz)) int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
uvmunmap(pagetable, newup, oldsz - newup, 1); uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
}
return newsz; return newsz;
} }
@ -298,7 +295,7 @@ void
uvmfree(pagetable_t pagetable, uint64 sz) uvmfree(pagetable_t pagetable, uint64 sz)
{ {
if(sz > 0) if(sz > 0)
uvmunmap(pagetable, 0, sz, 1); uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
freewalk(pagetable); freewalk(pagetable);
} }
@ -334,7 +331,7 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
return 0; return 0;
err: err:
uvmunmap(new, 0, i, 1); uvmunmap(new, 0, i / PGSIZE, 1);
return -1; return -1;
} }