diff options
author | jhb <jhb@FreeBSD.org> | 2007-05-08 21:49:59 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-05-08 21:49:59 +0000 |
commit | b5754be873ffc482e02f0ca0302ed02455308b6e (patch) | |
tree | 322b0315af31f7940110eaa9dddf0b0069170f03 /sys | |
parent | 23cec608a68684526dc8d307c87222af3aa2e0bf (diff) | |
download | FreeBSD-src-b5754be873ffc482e02f0ca0302ed02455308b6e.zip FreeBSD-src-b5754be873ffc482e02f0ca0302ed02455308b6e.tar.gz |
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).
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_condvar.c | 30 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 8 |
2 files changed, 32 insertions, 6 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index d31d993..80dd7ef 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -124,9 +124,13 @@ _cv_wait(struct cv *cvp, struct lock_object *lock) cvp->cv_waiters++; DROP_GIANT(); - lock_state = class->lc_unlock(lock); 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); #ifdef KTRACE @@ -173,9 +177,13 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) cvp->cv_waiters++; DROP_GIANT(); - class->lc_unlock(lock); 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); #ifdef KTRACE @@ -226,10 +234,14 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock) cvp->cv_waiters++; DROP_GIANT(); - lock_state = class->lc_unlock(lock); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 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); #ifdef KTRACE @@ -282,10 +294,14 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) cvp->cv_waiters++; DROP_GIANT(); - lock_state = class->lc_unlock(lock); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 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); #ifdef KTRACE @@ -341,11 +357,15 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) cvp->cv_waiters++; DROP_GIANT(); - lock_state = class->lc_unlock(lock); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE, 0); 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); #ifdef KTRACE diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 6e23d0d..d61dddf 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -182,7 +182,7 @@ _sleep(ident, lock, priority, wmesg, timo) td->td_tid, p->p_pid, p->p_comm, wmesg, ident); DROP_GIANT(); - if (lock != NULL) { + if (lock != NULL && !(class->lc_flags & LC_SLEEPABLE)) { WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); } else @@ -201,6 +201,12 @@ _sleep(ident, lock, priority, wmesg, timo) sleepq_add(ident, ident == &lbolt ? NULL : lock, wmesg, flags, 0); if (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. |