Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c +++ sys/kern/kern_timeout.c @@ -681,7 +681,8 @@ if (c->c_iflags & CALLOUT_LOCAL_ALLOC) c->c_iflags = CALLOUT_LOCAL_ALLOC; else - c->c_iflags &= ~CALLOUT_PENDING; + c->c_iflags &= ~(CALLOUT_PENDING | CALLOUT_PROCESSED); + c->c_iflags |= CALLOUT_RUNNING; cc_exec_curr(cc, direct) = c; cc_exec_cancel(cc, direct) = false; @@ -749,6 +750,7 @@ class->lc_unlock(c_lock); skip: CC_LOCK(cc); + c->c_iflags &= ~CALLOUT_RUNNING; KASSERT(cc_exec_curr(cc, direct) == c, ("mishandled cc_curr")); cc_exec_curr(cc, direct) = NULL; if (cc_exec_drain(cc, direct)) { @@ -1088,6 +1090,7 @@ LIST_REMOVE(c, c_links.le); } else { TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + c->c_iflags &= ~CALLOUT_PROCESSED; } cancelled = 1; c->c_iflags &= ~ CALLOUT_PENDING; @@ -1166,7 +1169,7 @@ struct callout_cpu *cc, *old_cc; struct lock_class *class; int direct, sq_locked, use_lock; - int not_on_a_list; + int cancelled, not_on_a_list; if ((flags & CS_DRAIN) != 0) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, c->c_lock, @@ -1240,7 +1243,7 @@ * don't attempt to remove it from the queue. We can try to * stop it by other means however. */ - if (!(c->c_iflags & CALLOUT_PENDING)) { + if (c->c_iflags & CALLOUT_RUNNING) { /* * If it wasn't on the queue and it isn't the current * callout, then we can't stop it, so just bail. @@ -1383,13 +1386,21 @@ if (drain) { cc_exec_drain(cc, direct) = drain; } - CC_UNLOCK(cc); KASSERT(!sq_locked, ("sleepqueue chain still locked")); - return (0); - } + cancelled = 0; + } else + cancelled = 1; + if (sq_locked) sleepq_release(&cc_exec_waiting(cc, direct)); + if ((c->c_iflags & CALLOUT_PENDING) == 0) { + CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", + c, c->c_func, c->c_arg); + CC_UNLOCK(cc); + return (cancelled); + } + c->c_iflags &= ~CALLOUT_PENDING; c->c_flags &= ~CALLOUT_ACTIVE; @@ -1402,11 +1413,12 @@ LIST_REMOVE(c, c_links.le); } else { TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + c->c_iflags &= ~CALLOUT_PROCESSED; } } callout_cc_del(c, cc); CC_UNLOCK(cc); - return (1); + return (cancelled); } void Index: sys/sys/callout.h =================================================================== --- sys/sys/callout.h +++ sys/sys/callout.h @@ -49,6 +49,7 @@ #define CALLOUT_DFRMIGRATION 0x0040 /* callout in deferred migration mode */ #define CALLOUT_PROCESSED 0x0080 /* callout in wheel or processing list? */ #define CALLOUT_DIRECT 0x0100 /* allow exec from hw int context */ +#define CALLOUT_RUNNING 0x0200 /* is now running */ #define C_DIRECT_EXEC 0x0001 /* direct execution of callout */ #define C_PRELBITS 7