Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jul 2026 04:05:43 -0700
From:      Kevin Bowling <kevin.bowling@kev009.com>
To:        Mark Johnston <markj@freebsd.org>
Cc:        src-committers@freebsd.org, dev-commits-src-all@freebsd.org,  dev-commits-src-main@freebsd.org
Subject:   Re: git: 1f4b0ea4f3eb - main - kqueue: Add a helper macro for sleeping on in-flux knotes
Message-ID:  <CAK7dMtDU8F=VAusGYYkEfAvxtRO%2BVB5MohjX=-sC1qbP_YE=mQ@mail.gmail.com>
In-Reply-To: <6a67e66f.32351.45a31bd3@gitrepo.freebsd.org>

index | next in thread | previous in thread | raw e-mail

Hi Mark,

This is resulting in relatively easy to trigger panic with 'syncthing'
running under INVARIANTS:
panic: kqueue_scan: knote 0xfffffe018aeab930 not on kqueue 0xfffff80010aa2400

The panic occurs at the new KASSERT in KQ_FLUX_SLEEP_WMESG(), called
from kqueue_scan() line 2197. Two Syncthing threads were concurrently
scanning the same kqueue.

kgdb showed that the knote named in the panic was exactly the other
scanning thread’s local marker:

&marker = 0xfffffe018aeab930
marker.kn_status = KN_MARKER
marker.kn_kq = NULL
kq = 0xfffff80010aa2400

I have the full backtraces if useful.

Regards,
Kevin

On Mon, Jul 27, 2026 at 4:15 PM Mark Johnston <markj@freebsd.org> wrote:
>
> The branch main has been updated by markj:
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=1f4b0ea4f3eb1b8a885eff8bd0d332156f0c3e1f
>
> commit 1f4b0ea4f3eb1b8a885eff8bd0d332156f0c3e1f
> Author:     Mark Johnston <markj@FreeBSD.org>
> AuthorDate: 2026-07-27 23:12:16 +0000
> Commit:     Mark Johnston <markj@FreeBSD.org>
> CommitDate: 2026-07-27 23:12:16 +0000
>
>     kqueue: Add a helper macro for sleeping on in-flux knotes
>
>     Other in-flux operations are implemented by this set of macros, so we
>     should do the same for sleeping.
>
>     No functional change intended.
>
>     Reviewed by:    kib
>     MFC after:      1 week
>     Sponsored by:   The FreeBSD Foundation
>     Differential Revision:  https://reviews.freebsd.org/D58443
> ---
>  sys/kern/kern_event.c | 32 ++++++++++++++++----------------
>  1 file changed, 16 insertions(+), 16 deletions(-)
>
> diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
> index 23e9d309f74c..60c3b18a07eb 100644
> --- a/sys/kern/kern_event.c
> +++ b/sys/kern/kern_event.c
> @@ -257,6 +257,14 @@ SYSCTL_UINT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW,
>                 wakeup((kq));                                           \
>         }                                                               \
>  } while (0)
> +#define KQ_FLUX_SLEEP_WMESG(kq, kn, flags, wmesg) do {                 \
> +       KASSERT((kn)->kn_kq == (kq),                                    \
> +           ("%s: knote %p not on kqueue %p", __func__, kn, kq));       \
> +       (kq)->kq_state |= KQ_FLUXWAIT;                                  \
> +       msleep((kq), &(kq)->kq_lock, PSOCK | (flags), (wmesg), 0);      \
> +} while (0)
> +#define KQ_FLUX_SLEEP(kq, kn, flags)                                   \
> +       KQ_FLUX_SLEEP_WMESG(kq, kn, flags, "kqfluxwt")
>  #define KQ_UNLOCK_FLUX(kq) do {                                                \
>         KQ_FLUX_WAKEUP(kq);                                             \
>         mtx_unlock(&(kq)->kq_lock);                                     \
> @@ -1789,8 +1797,7 @@ findkn:
>                         FILEDESC_XUNLOCK(td->td_proc->p_fd);
>                         filedesc_unlock = 0;
>                 }
> -               kq->kq_state |= KQ_FLUXWAIT;
> -               msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqflxwt", 0);
> +               KQ_FLUX_SLEEP(kq, kn, PDROP);
>                 if (fp != NULL) {
>                         fdrop(fp, td);
>                         fp = NULL;
> @@ -2187,9 +2194,7 @@ retry:
>                                 influx = 0;
>                                 KQ_FLUX_WAKEUP(kq);
>                         }
> -                       kq->kq_state |= KQ_FLUXWAIT;
> -                       error = msleep(kq, &kq->kq_lock, PSOCK,
> -                           "kqflxwt", 0);
> +                       KQ_FLUX_SLEEP(kq, kn, 0);
>                         continue;
>                 }
>
> @@ -2423,8 +2428,7 @@ kqueue_drain(struct kqueue *kq, struct thread *td)
>         for (i = 0; i < kq->kq_knlistsize; i++) {
>                 while ((kn = SLIST_FIRST(&kq->kq_knlist[i])) != NULL) {
>                         if (kn_in_flux(kn)) {
> -                               kq->kq_state |= KQ_FLUXWAIT;
> -                               msleep(kq, &kq->kq_lock, PSOCK, "kqclo1", 0);
> +                               KQ_FLUX_SLEEP_WMESG(kq, kn, 0, "kqclo1");
>                                 continue;
>                         }
>                         kn_enter_flux(kn);
> @@ -2437,9 +2441,8 @@ kqueue_drain(struct kqueue *kq, struct thread *td)
>                 for (i = 0; i <= kq->kq_knhashmask; i++) {
>                         while ((kn = SLIST_FIRST(&kq->kq_knhash[i])) != NULL) {
>                                 if (kn_in_flux(kn)) {
> -                                       kq->kq_state |= KQ_FLUXWAIT;
> -                                       msleep(kq, &kq->kq_lock, PSOCK,
> -                                              "kqclo2", 0);
> +                                       KQ_FLUX_SLEEP_WMESG(kq, kn, 0,
> +                                           "kqclo2");
>                                         continue;
>                                 }
>                                 kn_enter_flux(kn);
> @@ -2834,8 +2837,7 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
>                 KQ_LOCK(kq);
>                 KASSERT(kn_in_flux(kn), ("knote removed w/o list lock"));
>                 knl->kl_unlock(knl->kl_lockarg);
> -               kq->kq_state |= KQ_FLUXWAIT;
> -               msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqkclr", 0);
> +               KQ_FLUX_SLEEP_WMESG(kq, kn, PDROP, "kqkclr");
>                 kq = NULL;
>                 knl->kl_lock(knl->kl_lockarg);
>         }
> @@ -2881,8 +2883,7 @@ knote_fdclose(struct thread *td, int fd)
>                                  * the case that it's in the process of being
>                                  * dropped anyways.
>                                  */
> -                               kq->kq_state |= KQ_FLUXWAIT;
> -                               msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0);
> +                               KQ_FLUX_SLEEP(kq, kn, 0);
>                                 continue;
>                         }
>                         kn_enter_flux(kn);
> @@ -2946,8 +2947,7 @@ knote_drop_detached(struct knote *kn, struct thread *td)
>                     kn, kn->kn_influx));
>                 if (kn->kn_influx == 1)
>                         break;
> -               kq->kq_state |= KQ_FLUXWAIT;
> -               msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0);
> +               KQ_FLUX_SLEEP(kq, kn, 0);
>         }
>
>         MPASS(kn->kn_kq == kq);
>


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAK7dMtDU8F=VAusGYYkEfAvxtRO%2BVB5MohjX=-sC1qbP_YE=mQ>