On Mon, Jul 19, 2010 at 02:34:52PM +0200, Martin Pelik??n wrote:
> Hello everyone.
> Yesterday I compiled some stuff from ports, when my i386 -current (about
> two days old) paniced (onproc was one of those cc(1)):
> Debugger(), panic(),
> mtx_enter+0x5a(d0a2fc20, d2bae000, d2baf000, 0, 0)
> uvm_pseg_release+0x6b
> uvm_swap_allocpages+0x8d9
> uvm_swap_get+0x38
> uvm_fault_anonget+0x169
> uvm_fault+0x4bd(d2e83ec4, 88388000, 0, 1, cfbecb58)
> 
> "show panic" showed "mtx_enter: locking against myself". I probably
> went out of memory (just 128M ram + 300M swap). Lastly, I unfortunately
> mistyped "boot sync" instead of "boot crash", so I don't have any other
> information except from this small piece of paper :-(
> I found the place in the code, but don't really understand the meaning
> of the #ifdef DIAGNOSTIC blocks inside mutex.S in mtx_enter(). Can
> anyone explain me what is this check for?
> Thanks in advance, will post more details after I reproduce this.

Please test the following diff, it should help:

Index: uvm_pager.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_pager.c,v
retrieving revision 1.56
diff -u -p -r1.56 uvm_pager.c
--- uvm_pager.c 27 Jun 2010 20:53:31 -0000      1.56
+++ uvm_pager.c 19 Jul 2010 15:56:07 -0000
@@ -80,7 +80,7 @@ struct uvm_pseg {
        /* Bitmap of the segments in use in this pseg. */
        int     use;
 };
-struct mutex uvm_pseg_lck;
+struct rwlock uvm_pseg_lck = RWLOCK_INITIALIZER("pseg");
 struct uvm_pseg psegs[PSEG_NUMSEGS];
 
 #define UVM_PSEG_FULL(pseg)    ((pseg)->use == (1 << MAX_PAGER_SEGS) - 1)
@@ -108,7 +108,6 @@ uvm_pager_init(void)
         */
 
        uvm_pseg_init(&psegs[0]);
-       mtx_init(&uvm_pseg_lck, IPL_VM);
 
        /*
         * init ASYNC I/O queue
@@ -136,9 +135,10 @@ uvm_pager_init(void)
 void
 uvm_pseg_init(struct uvm_pseg *pseg)
 {
+       rw_assert_wrlock(&uvm_pseg_lck);
        KASSERT(pseg->start == 0);
        KASSERT(pseg->use == 0);
-       pseg->start = uvm_km_valloc_try(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
+       pseg->start = uvm_km_valloc(kernel_map, MAX_PAGER_SEGS * MAXBSIZE);
 }
 
 /*
@@ -153,6 +153,7 @@ uvm_pseg_init(struct uvm_pseg *pseg)
 void
 uvm_pseg_destroy(struct uvm_pseg *pseg)
 {
+       rw_assert_wrlock(&uvm_pseg_lck);
        KASSERT(pseg != &psegs[0]);
        KASSERT(pseg->start != 0);
        KASSERT(pseg->use == 0);
@@ -173,7 +174,8 @@ uvm_pseg_get(int flags)
        int i;
        struct uvm_pseg *pseg;
 
-       mtx_enter(&uvm_pseg_lck);
+       splassert(IPL_NONE);
+       rw_enter_write(&uvm_pseg_lck);
 
 pager_seg_restart:
        /* Find first pseg that has room. */
@@ -197,7 +199,7 @@ pager_seg_restart:
                for (; i < MAX_PAGER_SEGS; i++) {
                        if (!UVM_PSEG_INUSE(pseg, i)) {
                                pseg->use |= 1 << i;
-                               mtx_leave(&uvm_pseg_lck);
+                               rw_exit_write(&uvm_pseg_lck);
                                return pseg->start + i * MAXBSIZE;
                        }
                }
@@ -205,11 +207,23 @@ pager_seg_restart:
 
 pager_seg_fail:
        if ((flags & UVMPAGER_MAPIN_WAITOK) != 0) {
-               msleep(&psegs, &uvm_pseg_lck, PVM, "pagerseg", 0);
+               struct sleep_state sls;
+
+               /*
+                * Sleep atomically releasing the rwlock so we won't miss
+                * our wakeup.
+                */
+               sleep_setup(&sls, &psegs, PVM, "pseg_get");
+
+               rw_exit_write(&uvm_pseg_lck);
+
+               sleep_finish(&sls, 1);
+
+               rw_enter_write(&uvm_pseg_lck);
                goto pager_seg_restart;
        }
 
-       mtx_leave(&uvm_pseg_lck);
+       rw_exit_write(&uvm_pseg_lck);
        return 0;
 }
 
@@ -226,6 +240,7 @@ uvm_pseg_release(vaddr_t segaddr)
        int id;
        struct uvm_pseg *pseg;
 
+       splassert(IPL_NONE);
        for (pseg = &psegs[0]; pseg != &psegs[PSEG_NUMSEGS]; pseg++) {
                if (pseg->start <= segaddr &&
                    segaddr < pseg->start + MAX_PAGER_SEGS * MAXBSIZE)
@@ -239,7 +254,7 @@ uvm_pseg_release(vaddr_t segaddr)
        /* test for no remainder */
        KDASSERT(segaddr == pseg->start + id * MAXBSIZE);
 
-       mtx_enter(&uvm_pseg_lck);
+       rw_enter_write(&uvm_pseg_lck);
 
        KASSERT(UVM_PSEG_INUSE(pseg, id));
 
@@ -249,7 +264,7 @@ uvm_pseg_release(vaddr_t segaddr)
        if (pseg != &psegs[0] && UVM_PSEG_EMPTY(pseg))
                uvm_pseg_destroy(pseg);
 
-       mtx_leave(&uvm_pseg_lck);
+       rw_exit_write(&uvm_pseg_lck);
 }
 
 /*
> 
> -- 
> Martin Pelikan
> 

-- 
Noncombatant, n.:
        A dead Quaker.
                -- Ambrose Bierce

Reply via email to