summaryrefslogtreecommitdiff
path: root/sys/uvm
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2011-04-01 15:43:14 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2011-04-01 15:43:14 +0000
commitebab8c6780f01352ec496193ad4e52f48efcaad6 (patch)
tree3e5e5ee394487700b15423fb6cf4fb36f30bd185 /sys/uvm
parentcce7f2d68cc89fa3c340225738850e272d259068 (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.c27
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);
}