aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2026-04-01 22:30:48 +0000
committerKyle Evans <kevans@FreeBSD.org>2026-04-01 22:30:48 +0000
commit0b4f0e0515d0c7ec855cd654ae5dc562f4931cae (patch)
tree97fa32ae59a4bef8834e2d319293da1d10921a27
parent5d4a39d8ed775d607e0702f317f687491ac0a23d (diff)
kqueue: compare against the size in kqueue_expand
This is a cosmetic change, rather than a functional one: comparing the knlistsize against the fd requires a little bit of mental gymnastics to confirm that this is fine and not doing unnecessary work in some cases. Notably, one must consider that kq_knlistsize only grows in KQEXTENT chunks, which means that concurrent threads trying to grow the kqueue to consecutive fds will usually not result in the list being replaced twice. One can also more clearly rule out classes of arithmetic problems in the final `else` branch. Reviewed by: kib, markj Differential Revision: https://reviews.freebsd.org/D56209
-rw-r--r--sys/kern/kern_event.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index f984161bfcd6..2cdc37b710e6 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -2013,10 +2013,11 @@ kqueue_expand(struct kqueue *kq, const struct filterops *fops, uintptr_t ident,
to_free = NULL;
if (fops->f_isfd) {
fd = ident;
- if (kq->kq_knlistsize <= fd) {
- size = kq->kq_knlistsize;
- while (size <= fd)
+ size = atomic_load_int(&kq->kq_knlistsize);
+ if (size <= fd) {
+ do {
size += KQEXTENT;
+ } while (size <= fd);
list = malloc(size * sizeof(*list), M_KQUEUE, mflag);
if (list == NULL)
return ENOMEM;
@@ -2024,7 +2025,7 @@ kqueue_expand(struct kqueue *kq, const struct filterops *fops, uintptr_t ident,
if ((kq->kq_state & KQ_CLOSING) != 0) {
to_free = list;
error = EBADF;
- } else if (kq->kq_knlistsize > fd) {
+ } else if (kq->kq_knlistsize >= size) {
to_free = list;
} else {
if (kq->kq_knlist != NULL) {
@@ -2039,6 +2040,7 @@ kqueue_expand(struct kqueue *kq, const struct filterops *fops, uintptr_t ident,
kq->kq_knlistsize = size;
kq->kq_knlist = list;
}
+ MPASS(error != 0 || kq->kq_knlistsize > fd);
KQ_UNLOCK(kq);
}
} else {