diff options
author | jhb <jhb@FreeBSD.org> | 2001-03-28 16:11:51 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2001-03-28 16:11:51 +0000 |
commit | f96cb16a4adb80bbed4e5570638ca2b8a1edc96f (patch) | |
tree | 39662e8bbbe9d34367811e45b9667f17d0d363b7 /sys/kern/subr_witness.c | |
parent | 4d55d58720d6ddd6d85f7b32cb6ad850331dc6f2 (diff) | |
download | FreeBSD-src-f96cb16a4adb80bbed4e5570638ca2b8a1edc96f.zip FreeBSD-src-f96cb16a4adb80bbed4e5570638ca2b8a1edc96f.tar.gz |
Close a race condition where if we were obtaining a sleep lock and no spin
locks were held, we could be preempted and switch CPU's in between the time
that we set a variable to the list of spin locks on our CPU and the time
that we checked that variable to ensure no spinlocks were held while
grabbing a sleep lock. Losing the race resulted in checking some other
CPU's spin lock list and bogusly panicing.
Diffstat (limited to 'sys/kern/subr_witness.c')
-rw-r--r-- | sys/kern/subr_witness.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 862c20c..846ac7e 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -471,13 +471,26 @@ witness_lock(struct lock_object *lock, int flags, const char *file, int line) return; } + /* + * We have to hold a spinlock to keep lock_list valid across the check + * in the LC_SLEEPLOCK case. In the LC_SPINLOCK case, it is already + * protected by the spinlock we are currently performing the witness + * checks on, so it is ok to release the lock after performing this + * check. All we have to protect is the LC_SLEEPLOCK case when no + * spinlocks are held as we may get preempted during this check and + * lock_list could end up pointing to some other CPU's spinlock list. + */ + mtx_lock_spin(&w_mtx); lock_list = PCPU_PTR(spinlocks); if (class->lc_flags & LC_SLEEPLOCK) { - if (*lock_list != NULL) + if (*lock_list != NULL) { + mtx_unlock_spin(&w_mtx); panic("blockable sleep lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, file, line); + } lock_list = &p->p_sleeplocks; } + mtx_unlock_spin(&w_mtx); if (flags & LOP_TRYLOCK) goto out; |