Fix low-level locking during panics.

The SCHEDULER_STOPPED() hack breaks locking generally, and
mtx_trylock_*() especially.  When mtx_trylock_*() returns nonzero,
naive code version here trusts it to have worked.  But when
SCHEDULER_STOPPED() is true, mtx_trylock_*() returns 1 without doing
anything.  Then mtx_unlock_*() crashes especially badly attempting to
unlock iff the error is detected, since mutex unlocking functions don't
check SCHEDULER_STOPPED().

syscons already didn't trust mtx_trylock_spin(), but it was missing the
logic to turn on sp->kdb_locked when turning off sp->mtx_locked during
panics.  It also used panicstr instead of SCHEDULER_LOCKED because I
thought that panicstr was more fragile.  They only differ for a window
of lines in panic(), and in broken cases where stop_cpus_hard() in panic()
didn't work.
This commit is contained in:
bde 2018-06-02 08:38:59 +00:00
parent a8efb181f4
commit 14f65346d3

View File

@ -1807,13 +1807,19 @@ sccnscrlock(sc_softc_t *sc, struct sc_cnstate *sp)
* enough to ignore the protection even in the kdb_active case.
*/
if (kdb_active) {
sp->kdb_locked = sc->video_mtx.mtx_lock == MTX_UNOWNED || panicstr;
sp->kdb_locked = sc->video_mtx.mtx_lock == MTX_UNOWNED ||
SCHEDULER_STOPPED();
sp->mtx_locked = FALSE;
} else {
sp->kdb_locked = FALSE;
for (retries = 0; retries < 1000; retries++) {
sp->mtx_locked = mtx_trylock_spin_flags(&sc->video_mtx,
MTX_QUIET) != 0 || panicstr;
MTX_QUIET) != 0;
if (SCHEDULER_STOPPED()) {
sp->kdb_locked = TRUE;
sp->mtx_locked = FALSE;
break;
}
if (sp->mtx_locked)
break;
DELAY(1);