Don't sleep while holding the uvm_psel_lck mutex. Should fix "locking against
authorkettenis <kettenis@openbsd.org>
Sat, 24 Jul 2010 15:40:39 +0000 (15:40 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 24 Jul 2010 15:40:39 +0000 (15:40 +0000)
myself" panics that some people have seen over the last year-and-a-half.

Cherry picked from a more complex (and therefore scarier) diff from oga@.

ok tedu@, oga@

sys/uvm/uvm_pager.c

index 2e307af..f634cae 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uvm_pager.c,v 1.56 2010/06/27 20:53:31 oga Exp $      */
+/*     $OpenBSD: uvm_pager.c,v 1.57 2010/07/24 15:40:39 kettenis Exp $ */
 /*     $NetBSD: uvm_pager.c,v 1.36 2000/11/27 18:26:41 chs Exp $       */
 
 /*
@@ -88,7 +88,6 @@ struct        uvm_pseg psegs[PSEG_NUMSEGS];
 #define UVM_PSEG_INUSE(pseg,id)        (((pseg)->use & (1 << (id))) != 0)
 
 void           uvm_pseg_init(struct uvm_pseg *);
-void           uvm_pseg_destroy(struct uvm_pseg *);
 vaddr_t                uvm_pseg_get(int);
 void           uvm_pseg_release(vaddr_t);
 
@@ -141,25 +140,6 @@ uvm_pseg_init(struct uvm_pseg *pseg)
        pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
 }
 
-/*
- * Destroy a uvm_pseg.
- *
- * Never fails.
- *
- * Requires that seg != &psegs[0]
- *
- * Caller locks uvm_pseg_lck.
- */
-void
-uvm_pseg_destroy(struct uvm_pseg *pseg)
-{
-       KASSERT(pseg != &psegs[0]);
-       KASSERT(pseg->start != 0);
-       KASSERT(pseg->use == 0);
-       uvm_km_free(kernel_map, pseg->start, MAX_PAGER_SEGS * MAXBSIZE);
-       pseg->start = 0;
-}
-
 /*
  * Acquire a pager map segment.
  *
@@ -225,6 +205,7 @@ uvm_pseg_release(vaddr_t segaddr)
 {
        int id;
        struct uvm_pseg *pseg;
+       vaddr_t va = 0;
 
        for (pseg = &psegs[0]; pseg != &psegs[PSEG_NUMSEGS]; pseg++) {
                if (pseg->start <= segaddr &&
@@ -246,10 +227,15 @@ uvm_pseg_release(vaddr_t segaddr)
        pseg->use &= ~(1 << id);
        wakeup(&psegs);
 
-       if (pseg != &psegs[0] && UVM_PSEG_EMPTY(pseg))
-               uvm_pseg_destroy(pseg);
+       if (pseg != &psegs[0] && UVM_PSEG_EMPTY(pseg)) {
+               va = pseg->start;
+               pseg->start = 0;
+       }
 
        mtx_leave(&uvm_pseg_lck);
+
+       if (va)
+               uvm_km_free(kernel_map, va, MAX_PAGER_SEGS * MAXBSIZE);
 }
 
 /*