diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2011-04-01 15:43:14 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2011-04-01 15:43:14 +0000 |
commit | ebab8c6780f01352ec496193ad4e52f48efcaad6 (patch) | |
tree | 3e5e5ee394487700b15423fb6cf4fb36f30bd185 /sys/uvm | |
parent | cce7f2d68cc89fa3c340225738850e272d259068 (diff) |
Two problems with vslock_device functions.
- Fix error handling so that we free stuff on error.
- We use the mappings to keep track of which pages need to be
freed so don't unmap before freeing (this is theoretically
incorrect and will be fixed soon).
This makes fsck happy on bigmem machines (it doesn't leak all
dma:able memory anymore).
beck@, drahn@, oga@ ok
Diffstat (limited to 'sys/uvm')
-rw-r--r-- | sys/uvm/uvm_glue.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/sys/uvm/uvm_glue.c b/sys/uvm/uvm_glue.c index 4cc0d631c4d..74599ba8268 100644 --- a/sys/uvm/uvm_glue.c +++ b/sys/uvm/uvm_glue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_glue.c,v 1.55 2010/07/02 22:38:32 thib Exp $ */ +/* $OpenBSD: uvm_glue.c,v 1.56 2011/04/01 15:43:13 art Exp $ */ /* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */ /* @@ -222,8 +222,10 @@ uvm_vslock_device(struct proc *p, void *addr, size_t len, paddr_t pa; if (!pmap_extract(p->p_vmspace->vm_map.pmap, - start + ptoa(i), &pa)) - return (EFAULT); + start + ptoa(i), &pa)) { + error = EFAULT; + goto out_unwire; + } if (!PADDR_IS_DMA_REACHABLE(pa)) break; } @@ -233,13 +235,15 @@ uvm_vslock_device(struct proc *p, void *addr, size_t len, } if ((va = uvm_km_valloc(kernel_map, sz)) == 0) { - return (ENOMEM); + error = ENOMEM; + goto out_unwire; } TAILQ_INIT(&pgl); error = uvm_pglistalloc(npages * PAGE_SIZE, dma_constraint.ucr_low, dma_constraint.ucr_high, 0, 0, &pgl, npages, UVM_PLA_WAITOK); - KASSERT(error == 0); + if (error) + goto out_unmap; sva = va; while ((pg = TAILQ_FIRST(&pgl)) != NULL) { @@ -252,7 +256,16 @@ uvm_vslock_device(struct proc *p, void *addr, size_t len, KASSERT(va == sva + sz); *retp = (void *)(sva + off); - error = copyin(addr, *retp, len); + if ((error = copyin(addr, *retp, len)) == 0) + return 0; + + uvm_km_pgremove_intrsafe(sva, sva + sz); + pmap_kremove(sva, sz); + pmap_update(pmap_kernel()); +out_unmap: + uvm_km_free(kernel_map, sva, sz); +out_unwire: + uvm_fault_unwire(&p->p_vmspace->vm_map, start, end); return (error); } @@ -277,9 +290,9 @@ uvm_vsunlock_device(struct proc *p, void *addr, size_t len, void *map) return; kva = trunc_page((vaddr_t)map); + uvm_km_pgremove_intrsafe(kva, kva + sz); pmap_kremove(kva, sz); pmap_update(pmap_kernel()); - uvm_km_pgremove_intrsafe(kva, kva + sz); uvm_km_free(kernel_map, kva, sz); } |