--- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1377,6 +1377,15 @@ if (oid == NULL) return (ENOENT); + /* + * A DYING oid is being torn down and its handler may + * vanish at any moment (the remover drops the xlock + * while draining running handlers). Report it as gone + * instead of dispatching into it. + */ + if (oid->oid_kind & CTLFLAG_DYING) + return (ENOENT); + indx++; if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { if (oid->oid_handler != NULL || indx == namelen) { @@ -1473,6 +1482,16 @@ #endif } + /* + * Count in-flight handler executions so that + * sysctl_remove_oid_locked() can drain them before freeing a + * dynamic oid during module teardown. Without this counter + * the CTLFLAG_DYING drain in sysctl_remove_oid_locked() is + * dead code: nothing else in the kernel ever touches + * oid_running. + */ + atomic_add_int(&oid->oid_running, 1); + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx, req); @@ -1480,6 +1499,9 @@ error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2, req); + if (atomic_fetchadd_int(&oid->oid_running, -1) == 1) + wakeup(&oid->oid_running); + if ((oid->oid_kind & CTLFLAG_NOLOCK) == 0) lockmgr(&oid->oid_lock, LK_RELEASE); return (error);