summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-04-14 14:27:28 +0000
committerjhb <jhb@FreeBSD.org>2006-04-14 14:27:28 +0000
commitdb475d0075885a1eff57e10d6c13f2f711ffdb12 (patch)
tree63f86e7f51f31342ce7d52b2a8530a76bbb5453e /sys/kern
parent5eb49ee7ff54b2979444993f7744834149d1951a (diff)
downloadFreeBSD-src-db475d0075885a1eff57e10d6c13f2f711ffdb12.zip
FreeBSD-src-db475d0075885a1eff57e10d6c13f2f711ffdb12.tar.gz
Drop the kqueue global mutex as soon as we are finished with it rather
than keeping it locked until we exit the function to optimize the case where the lock would be dropped and later reacquired. The optimization was broken when kevent's were moved from UFS to VFS and the knote list lock for a vnode kevent became the lockmgr vnode lock. If one tried to use a kqueue that contained events for a kqueue fd followed by a vnode, then the kq global lock would end up being held when the vnode lock was acquired which could result in sleeping with a mutex held (and subsequent panics) if the vnode lock was contested. Reviewed by: jmg Tested by: ps (on 6.x) MFC after: 3 days
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_event.c6
1 files changed, 2 insertions, 4 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 594c5f0..e629bbc 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1181,7 +1181,6 @@ start:
if (timeout < 0) {
error = EWOULDBLOCK;
} else {
- KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
kq->kq_state |= KQ_SLEEP;
error = msleep(kq, &kq->kq_lock, PSOCK | PCATCH,
"kqread", timeout);
@@ -1203,7 +1202,6 @@ start:
if ((kn->kn_status == KN_MARKER && kn != marker) ||
(kn->kn_status & KN_INFLUX) == KN_INFLUX) {
- KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
kq->kq_state |= KQ_FLUXWAIT;
error = msleep(kq, &kq->kq_lock, PSOCK,
"kqflxwt", 0);
@@ -1248,6 +1246,7 @@ start:
KN_LIST_LOCK(kn);
if (kn->kn_fop->f_event(kn, 0) == 0) {
KQ_LOCK(kq);
+ KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
kn->kn_status &=
~(KN_QUEUED | KN_ACTIVE | KN_INFLUX);
kq->kq_count--;
@@ -1256,6 +1255,7 @@ start:
}
*kevp = kn->kn_kevent;
KQ_LOCK(kq);
+ KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
if (kn->kn_flags & EV_CLEAR) {
kn->kn_data = 0;
kn->kn_fflags = 0;
@@ -1266,7 +1266,6 @@ start:
kn->kn_status &= ~(KN_INFLUX);
KN_LIST_UNLOCK(kn);
-
}
/* we are returning a copy to the user */
@@ -1288,7 +1287,6 @@ start:
done:
KQ_OWNED(kq);
KQ_UNLOCK_FLUX(kq);
- KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
knote_free(marker);
done_nl:
KQ_NOTOWNED(kq);
OpenPOWER on IntegriCloud