Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c (revision 238497) +++ sys/kern/kern_timeout.c (working copy) @@ -118,6 +118,7 @@ struct callout_cpu { struct callout_list cc_callfree; struct callout *cc_next; struct callout *cc_curr; + struct callout *cc_curr_direct; struct bintime cc_firstevent; struct bintime cc_lastscan; void *cc_cookie; @@ -385,9 +386,16 @@ callout_process(struct bintime *now) * directly from hardware interrupt context. */ if (tmp->c_flags & CALLOUT_DIRECT) { + cc->cc_curr_direct = tmp; + mtx_unlock_spin_flags(&cc->cc_lock, + MTX_QUIET); tmp->c_func(tmp->c_arg); - TAILQ_REMOVE(sc, tmp, c_links.tqe); - tmp->c_flags &= ~CALLOUT_PENDING; + wakeup(&cc->cc_waiting); + mtx_lock_spin_flags(&cc->cc_lock, + MTX_QUIET); + TAILQ_REMOVE(sc, tmp, c_links.tqe); + tmp->c_flags &= ~CALLOUT_PENDING; + cc->cc_curr_direct = NULL; } else { TAILQ_INSERT_TAIL(&cc->cc_expireq, tmp, c_staiter); @@ -908,7 +916,7 @@ _callout_reset_on(struct callout *c, struct bintim if (c->c_flags & CALLOUT_LOCAL_ALLOC) cpu = c->c_cpu; cc = callout_lock(c); - if (cc->cc_curr == c) { + if (cc->cc_curr == c || cc->cc_curr_direct == c) { /* * We're being asked to reschedule a callout which is * currently in progress. If there is a lock then we @@ -951,7 +959,7 @@ _callout_reset_on(struct callout *c, struct bintim * to a more appropriate moment. */ if (c->c_cpu != cpu) { - if (cc->cc_curr == c) { + if (cc->cc_curr == c || cc->cc_curr_direct == c) { cc->cc_migration_cpu = cpu; cc->cc_migration_time = to_bt; cc->cc_migration_func = ftn; @@ -1050,7 +1058,7 @@ again: * If it wasn't on the queue and it isn't the current * callout, then we can't stop it, so just bail. */ - if (cc->cc_curr != c) { + if (cc->cc_curr != c || cc->cc_curr_direct != c) { CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", c, c->c_func, c->c_arg); CC_UNLOCK(cc); @@ -1066,7 +1074,7 @@ again: * just wait for the current invocation to * finish. */ - while (cc->cc_curr == c) { + while (cc->cc_curr == c || cc->cc_curr_direct == c) { /* * Use direct calls to sleepqueue interface