svn commit: r256074 - stable/9/sys/kern
Konstantin Belousov
kib at FreeBSD.org
Sun Oct 6 05:50:56 UTC 2013
Author: kib
Date: Sun Oct 6 05:50:55 2013
New Revision: 256074
URL: http://svnweb.freebsd.org/changeset/base/256074
Log:
MFC r255798:
Pre-acquire the filedesc sx when a possibility exists that the later
code could need to remove a kqueue from the filedesc list.
Modified:
stable/9/sys/kern/kern_event.c
Directory Properties:
stable/9/sys/ (props changed)
Modified: stable/9/sys/kern/kern_event.c
==============================================================================
--- stable/9/sys/kern/kern_event.c Sat Oct 5 23:11:01 2013 (r256073)
+++ stable/9/sys/kern/kern_event.c Sun Oct 6 05:50:55 2013 (r256074)
@@ -965,12 +965,13 @@ kqueue_register(struct kqueue *kq, struc
struct file *fp;
struct knote *kn, *tkn;
int error, filt, event;
- int haskqglobal;
+ int haskqglobal, filedesc_unlock;
fp = NULL;
kn = NULL;
error = 0;
haskqglobal = 0;
+ filedesc_unlock = 0;
filt = kev->filter;
fops = kqueue_fo_find(filt);
@@ -1010,6 +1011,13 @@ findkn:
goto done;
}
+ /*
+ * Pre-lock the filedesc before the global
+ * lock mutex, see the comment in
+ * kqueue_close().
+ */
+ FILEDESC_XLOCK(td->td_proc->p_fd);
+ filedesc_unlock = 1;
KQ_GLOBAL_LOCK(&kq_global, haskqglobal);
}
@@ -1039,6 +1047,10 @@ findkn:
/* knote is in the process of changing, wait for it to stablize. */
if (kn != NULL && (kn->kn_status & KN_INFLUX) == KN_INFLUX) {
KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
+ if (filedesc_unlock) {
+ FILEDESC_XUNLOCK(td->td_proc->p_fd);
+ filedesc_unlock = 0;
+ }
kq->kq_state |= KQ_FLUXWAIT;
msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqflxwt", 0);
if (fp != NULL) {
@@ -1155,6 +1167,8 @@ done_ev_add:
done:
KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
+ if (filedesc_unlock)
+ FILEDESC_XUNLOCK(td->td_proc->p_fd);
if (fp != NULL)
fdrop(fp, td);
if (tkn != NULL)
@@ -1642,10 +1656,12 @@ kqueue_close(struct file *fp, struct thr
struct knote *kn;
int i;
int error;
+ int filedesc_unlock;
if ((error = kqueue_acquire(fp, &kq)))
return error;
+ filedesc_unlock = 0;
KQ_LOCK(kq);
KASSERT((kq->kq_state & KQ_CLOSING) != KQ_CLOSING,
@@ -1707,9 +1723,20 @@ kqueue_close(struct file *fp, struct thr
KQ_UNLOCK(kq);
- FILEDESC_XLOCK(fdp);
+ /*
+ * We could be called due to the knote_drop() doing fdrop(),
+ * called from kqueue_register(). In this case the global
+ * lock is owned, and filedesc sx is locked before, to not
+ * take the sleepable lock after non-sleepable.
+ */
+ if (!sx_xlocked(FILEDESC_LOCK(fdp))) {
+ FILEDESC_XLOCK(fdp);
+ filedesc_unlock = 1;
+ } else
+ filedesc_unlock = 0;
TAILQ_REMOVE(&fdp->fd_kqlist, kq, kq_list);
- FILEDESC_XUNLOCK(fdp);
+ if (filedesc_unlock)
+ FILEDESC_XUNLOCK(fdp);
seldrain(&kq->kq_sel);
knlist_destroy(&kq->kq_sel.si_note);
More information about the svn-src-stable-9
mailing list