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