--- //depot/projects/smpng/sys/amd64/amd64/trap.c 2005/07/07 19:45:15 +++ //depot/user/jhb/lock/amd64/amd64/trap.c 2005/07/07 21:22:43 @@ -218,10 +218,10 @@ printf("kernel trap %d with interrupts disabled\n", type); /* - * We shouldn't enable interrupts while in a critical - * section. + * We shouldn't enable interrupts while holding a + * spin lock. */ - if (td->td_critnest == 0) + if (td->td_md.md_spinlock_count == 0) enable_intr(); } } @@ -235,8 +235,16 @@ * do the VM lookup, so just consider it a fatal trap so the * kernel can print out a useful trap message and even get * to the debugger. + * + * If we get a page fault while holding a non-sleepable + * lock, then it is most likely a fatal kernel page fault. + * If WITNESS is enabled, then it's going to whine about + * bogus LORs with various VM locks, so just skip to the + * fatal trap handling directly. */ - if (td->td_critnest != 0) + if (td->td_critnest != 0 || + WITNESS_WARN(WARN_SLEEPOK | WARN_GIANTOK, NULL, + "Kernel page fault") != 0) trap_fatal(&frame, frame.tf_addr); } --- //depot/projects/smpng/sys/arm/arm/trap.c 2005/06/24 18:10:31 +++ //depot/user/jhb/lock/arm/arm/trap.c 2005/06/24 19:07:24 @@ -265,7 +265,8 @@ /* Grab the current pcb */ pcb = td->td_pcb; /* Re-enable interrupts if they were enabled previously */ - if (td->td_critnest == 0 && __predict_true(tf->tf_spsr & I32_bit) == 0) + if (td->td_md.md_spinlock_count == 0 && + __predict_true(tf->tf_spsr & I32_bit) == 0) enable_interrupts(I32_bit); /* Invoke the appropriate handler, if necessary */ @@ -725,7 +726,7 @@ thread_user_enter(td); } fault_pc = tf->tf_pc; - if (td->td_critnest == 0 && + if (td->td_md.md_spinlock_count == 0 && __predict_true((tf->tf_spsr & I32_bit) == 0)) enable_interrupts(I32_bit); @@ -1003,7 +1004,7 @@ * Since all syscalls *should* come from user mode it will always * be safe to enable them, but check anyway. */ - if (td->td_critnest == 0 && !(frame->tf_spsr & I32_bit)) + if (td->td_md.md_spinlock_count == 0 && !(frame->tf_spsr & I32_bit)) enable_interrupts(I32_bit); syscall(td, frame, insn); --- //depot/projects/smpng/sys/i386/i386/trap.c 2005/07/13 18:25:40 +++ //depot/user/jhb/lock/i386/i386/trap.c 2005/07/13 18:39:33 @@ -239,11 +239,11 @@ type); /* * Page faults need interrupts disabled until later, - * and we shouldn't enable interrupts while in a - * critical section or if servicing an NMI. + * and we shouldn't enable interrupts while holding + * a spin lock or if servicing an NMI. */ if (type != T_NMI && type != T_PAGEFLT && - td->td_critnest == 0) + td->td_md.md_spinlock_count == 0) enable_intr(); } } @@ -264,12 +264,20 @@ * do the VM lookup, so just consider it a fatal trap so the * kernel can print out a useful trap message and even get * to the debugger. + * + * If we get a page fault while holding a non-sleepable + * lock, then it is most likely a fatal kernel page fault. + * If WITNESS is enabled, then it's going to whine about + * bogus LORs with various VM locks, so just skip to the + * fatal trap handling directly. */ eva = rcr2(); - if (td->td_critnest == 0) + if (td->td_critnest != 0 || + WITNESS_WARN(WARN_SLEEPOK | WARN_GIANTOK, NULL, + "Kernel page fault") != 0) + trap_fatal(&frame, eva); + else enable_intr(); - else - trap_fatal(&frame, eva); } #ifdef DEVICE_POLLING --- //depot/projects/smpng/sys/kern/kern_mutex.c 2005/07/14 17:21:42 +++ //depot/user/jhb/lock/kern/kern_mutex.c 2005/07/14 21:42:14 @@ -411,13 +415,16 @@ int rval; MPASS(curthread != NULL); + KASSERT(m->mtx_object.lo_class == &lock_class_mtx_sleep, + ("mtx_trylock() of spin mutex %s @ %s:%d", m->mtx_object.lo_name, + file, line)); if (mtx_owned(m) && (m->mtx_object.lo_flags & LO_RECURSABLE) != 0) { m->mtx_recurse++; atomic_set_ptr(&m->mtx_lock, MTX_RECURSED); rval = 1; } else rval = _obtain_lock(m, curthread); LOCK_LOG_TRY("LOCK", &m->mtx_object, opts, rval, file, line); if (rval) @@ -459,6 +467,15 @@ return; } + /* + * If we have already panic'd and this is the thread that called + * panic(), then don't block on any mutexes but silently succeed. + * Otherwise, the kernel will deadlock since the scheduler isn't + * going to run the thread that holds the lock we need. + */ + if (panicstr != NULL && curthread->td_flags & TDF_INPANIC) + return; + if (LOCK_LOG_TEST(&m->mtx_object, opts)) CTR4(KTR_LOCK, "_mtx_lock_sleep: %s contested (lock=%p) at %s:%d", @@ -606,7 +624,7 @@ } if (i < 60000000) DELAY(1); - else if (!kdb_active) { + else if (!kdb_active && !panicstr) { printf("spin lock %s held by %p for > 5 seconds\n", m->mtx_object.lo_name, (void *)m->mtx_lock); #ifdef WITNESS @@ -653,6 +671,15 @@ return; } + /* + * If we failed to unlock this lock and we are a thread that has + * called panic(), it may be due to the bypass in _mtx_lock_sleep() + * above. In that case, just return and leave the lock alone to + * avoid changing the state. + */ + if (panicstr != NULL && curthread->td_flags & TDF_INPANIC) + return; + turnstile_lock(&m->mtx_object); ts = turnstile_lookup(&m->mtx_object); if (LOCK_LOG_TEST(&m->mtx_object, opts)) --- //depot/projects/smpng/sys/sys/lock.h 2005/05/27 14:58:46 +++ //depot/user/jhb/lock/sys/lock.h 2005/05/27 18:31:22 @@ -276,7 +276,7 @@ #define WITNESS_UPGRADE(lock, flags, file, line) #define WITNESS_DOWNGRADE(lock, flags, file, line) #define WITNESS_UNLOCK(lock, flags, file, line) -#define WITNESS_WARN(flags, lock, fmt, ...) +#define WITNESS_WARN(flags, lock, fmt, ...) 0 #define WITNESS_SAVE_DECL(n) #define WITNESS_SAVE(lock, n) #define WITNESS_RESTORE(lock, n)