Fix a potential LOR with sx_sleep() and cv_wait() with sx locks by
1) adding the thread to the sleepq via sleepq_add() before dropping the lock, and 2) dropping the sleepq lock around calls to lc_unlock() for sleepable locks (i.e. locks that use sleepq's in their implementation).
This commit is contained in:
parent
fb610ca1f9
commit
9fa7ce0f23
@ -124,9 +124,13 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
|
|||||||
|
|
||||||
cvp->cv_waiters++;
|
cvp->cv_waiters++;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
lock_state = class->lc_unlock(lock);
|
|
||||||
|
|
||||||
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_release(cvp);
|
||||||
|
lock_state = class->lc_unlock(lock);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_lock(cvp);
|
||||||
sleepq_wait(cvp);
|
sleepq_wait(cvp);
|
||||||
|
|
||||||
#ifdef KTRACE
|
#ifdef KTRACE
|
||||||
@ -173,9 +177,13 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
|
|||||||
|
|
||||||
cvp->cv_waiters++;
|
cvp->cv_waiters++;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
class->lc_unlock(lock);
|
|
||||||
|
|
||||||
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_release(cvp);
|
||||||
|
class->lc_unlock(lock);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_lock(cvp);
|
||||||
sleepq_wait(cvp);
|
sleepq_wait(cvp);
|
||||||
|
|
||||||
#ifdef KTRACE
|
#ifdef KTRACE
|
||||||
@ -226,10 +234,14 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
|
|||||||
|
|
||||||
cvp->cv_waiters++;
|
cvp->cv_waiters++;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
lock_state = class->lc_unlock(lock);
|
|
||||||
|
|
||||||
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
|
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
|
||||||
SLEEPQ_INTERRUPTIBLE, 0);
|
SLEEPQ_INTERRUPTIBLE, 0);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_release(cvp);
|
||||||
|
lock_state = class->lc_unlock(lock);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_lock(cvp);
|
||||||
rval = sleepq_wait_sig(cvp);
|
rval = sleepq_wait_sig(cvp);
|
||||||
|
|
||||||
#ifdef KTRACE
|
#ifdef KTRACE
|
||||||
@ -282,10 +294,14 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
|
|||||||
|
|
||||||
cvp->cv_waiters++;
|
cvp->cv_waiters++;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
lock_state = class->lc_unlock(lock);
|
|
||||||
|
|
||||||
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
|
||||||
sleepq_set_timeout(cvp, timo);
|
sleepq_set_timeout(cvp, timo);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_release(cvp);
|
||||||
|
lock_state = class->lc_unlock(lock);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_lock(cvp);
|
||||||
rval = sleepq_timedwait(cvp);
|
rval = sleepq_timedwait(cvp);
|
||||||
|
|
||||||
#ifdef KTRACE
|
#ifdef KTRACE
|
||||||
@ -341,11 +357,15 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
|
|||||||
|
|
||||||
cvp->cv_waiters++;
|
cvp->cv_waiters++;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
lock_state = class->lc_unlock(lock);
|
|
||||||
|
|
||||||
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
|
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
|
||||||
SLEEPQ_INTERRUPTIBLE, 0);
|
SLEEPQ_INTERRUPTIBLE, 0);
|
||||||
sleepq_set_timeout(cvp, timo);
|
sleepq_set_timeout(cvp, timo);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_release(cvp);
|
||||||
|
lock_state = class->lc_unlock(lock);
|
||||||
|
if (class->lc_flags & LC_SLEEPABLE)
|
||||||
|
sleepq_lock(cvp);
|
||||||
rval = sleepq_timedwait_sig(cvp);
|
rval = sleepq_timedwait_sig(cvp);
|
||||||
|
|
||||||
#ifdef KTRACE
|
#ifdef KTRACE
|
||||||
|
@ -182,7 +182,7 @@ _sleep(ident, lock, priority, wmesg, timo)
|
|||||||
td->td_tid, p->p_pid, p->p_comm, wmesg, ident);
|
td->td_tid, p->p_pid, p->p_comm, wmesg, ident);
|
||||||
|
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
if (lock != NULL) {
|
if (lock != NULL && !(class->lc_flags & LC_SLEEPABLE)) {
|
||||||
WITNESS_SAVE(lock, lock_witness);
|
WITNESS_SAVE(lock, lock_witness);
|
||||||
lock_state = class->lc_unlock(lock);
|
lock_state = class->lc_unlock(lock);
|
||||||
} else
|
} else
|
||||||
@ -201,6 +201,12 @@ _sleep(ident, lock, priority, wmesg, timo)
|
|||||||
sleepq_add(ident, ident == &lbolt ? NULL : lock, wmesg, flags, 0);
|
sleepq_add(ident, ident == &lbolt ? NULL : lock, wmesg, flags, 0);
|
||||||
if (timo)
|
if (timo)
|
||||||
sleepq_set_timeout(ident, timo);
|
sleepq_set_timeout(ident, timo);
|
||||||
|
if (lock != NULL && class->lc_flags & LC_SLEEPABLE) {
|
||||||
|
sleepq_release(ident);
|
||||||
|
WITNESS_SAVE(lock, lock_witness);
|
||||||
|
lock_state = class->lc_unlock(lock);
|
||||||
|
sleepq_lock(ident);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust this thread's priority, if necessary.
|
* Adjust this thread's priority, if necessary.
|
||||||
|
Loading…
Reference in New Issue
Block a user