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