diff options
author | truckman <truckman@FreeBSD.org> | 2002-10-03 06:03:26 +0000 |
---|---|---|
committer | truckman <truckman@FreeBSD.org> | 2002-10-03 06:03:26 +0000 |
commit | 8ad27d99229f14a15d5975b533483bb4b6c065a8 (patch) | |
tree | 6447bcd1f2efaba7ac0961f75fbf3bc6900c4e2a | |
parent | cea0ea5b91ba3c35928089c6b4b279f60ab99c94 (diff) | |
download | FreeBSD-src-8ad27d99229f14a15d5975b533483bb4b6c065a8.zip FreeBSD-src-8ad27d99229f14a15d5975b533483bb4b6c065a8.tar.gz |
hashinit() calls MALLOC(), so release the filedesc lock in knote_attach()
before calling hashinit() and relock afterwards, taking care to see that
we don't lose a race.
-rw-r--r-- | sys/kern/kern_event.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index d8bc894..02402f9 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -953,15 +953,27 @@ knote_fdclose(struct thread *td, int fd) static void knote_attach(struct knote *kn, struct filedesc *fdp) { - struct klist *list, *oldlist; + struct klist *list, *oldlist, *tmp_knhash; + u_long tmp_knhashmask; int size, newsize; FILEDESC_LOCK(fdp); if (! kn->kn_fop->f_isfd) { - if (fdp->fd_knhashmask == 0) - fdp->fd_knhash = hashinit(KN_HASHSIZE, M_KQUEUE, - &fdp->fd_knhashmask); + if (fdp->fd_knhashmask == 0) { + FILEDESC_UNLOCK(fdp); + tmp_knhash = hashinit(KN_HASHSIZE, M_KQUEUE, + &tmp_knhashmask); + FILEDESC_LOCK(fdp); + if (fdp->fd_knhashmask == 0) { + fdp->fd_knhash = tmp_knhash; + fdp->fd_knhashmask = tmp_knhashmask; + } else { + FILEDESC_UNLOCK(fdp); + free(tmp_knhash, M_KQUEUE); + FILEDESC_LOCK(fdp); + } + } list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)]; goto done; } |