aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2018-11-28 18:06:16 +0000
committerMark Johnston <markj@FreeBSD.org>2018-11-28 18:06:16 +0000
commit3a2ceb530c5d8c5b0e9c3a74a2cdc9d4cb2e3dd7 (patch)
tree1f035353316e90fc858027c27b5a3f2842b8d846
parentc8a5b4f24be644bd936bb3d2181d6a69abd9502e (diff)
MFstable/12 r341082:
Ensure that knotes do not get registered when KQ_CLOSING is set. PR: 228858 Approved by: re (gjb)
Notes
Notes: svn path=/releng/12.0/; revision=341159
-rw-r--r--sys/kern/kern_event.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index b29f1bb86c01..94d0fcd0b261 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1463,8 +1463,11 @@ findkn:
break;
}
} else {
- if ((kev->flags & EV_ADD) == EV_ADD)
- kqueue_expand(kq, fops, kev->ident, waitok);
+ if ((kev->flags & EV_ADD) == EV_ADD) {
+ error = kqueue_expand(kq, fops, kev->ident, waitok);
+ if (error != 0)
+ goto done;
+ }
KQ_LOCK(kq);
@@ -1700,12 +1703,12 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
{
struct klist *list, *tmp_knhash, *to_free;
u_long tmp_knhashmask;
- int size;
- int fd;
+ int error, fd, size;
int mflag = waitok ? M_WAITOK : M_NOWAIT;
KQ_NOTOWNED(kq);
+ error = 0;
to_free = NULL;
if (fops->f_isfd) {
fd = ident;
@@ -1717,9 +1720,11 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
if (list == NULL)
return ENOMEM;
KQ_LOCK(kq);
- if (kq->kq_knlistsize > fd) {
+ if ((kq->kq_state & KQ_CLOSING) != 0) {
+ to_free = list;
+ error = EBADF;
+ } else if (kq->kq_knlistsize > fd) {
to_free = list;
- list = NULL;
} else {
if (kq->kq_knlist != NULL) {
bcopy(kq->kq_knlist, list,
@@ -1740,9 +1745,12 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
tmp_knhash = hashinit(KN_HASHSIZE, M_KQUEUE,
&tmp_knhashmask);
if (tmp_knhash == NULL)
- return ENOMEM;
+ return (ENOMEM);
KQ_LOCK(kq);
- if (kq->kq_knhashmask == 0) {
+ if ((kq->kq_state & KQ_CLOSING) != 0) {
+ to_free = tmp_knhash;
+ error = EBADF;
+ } else if (kq->kq_knhashmask == 0) {
kq->kq_knhash = tmp_knhash;
kq->kq_knhashmask = tmp_knhashmask;
} else {
@@ -1754,7 +1762,7 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
free(to_free, M_KQUEUE);
KQ_NOTOWNED(kq);
- return 0;
+ return (error);
}
static void
@@ -2605,6 +2613,8 @@ knote_attach(struct knote *kn, struct kqueue *kq)
KASSERT(kn_in_flux(kn), ("knote %p not marked influx", kn));
KQ_OWNED(kq);
+ if ((kq->kq_state & KQ_CLOSING) != 0)
+ return (EBADF);
if (kn->kn_fop->f_isfd) {
if (kn->kn_id >= kq->kq_knlistsize)
return (ENOMEM);