Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c (revision 216511) +++ sys/kern/kern_timeout.c (working copy) @@ -115,6 +115,7 @@ #ifdef SMP struct callout_cpu cc_cpu[MAXCPU]; +#define CPUBLOCK (MAXCPU + 1) #define CC_CPU(cpu) (&cc_cpu[(cpu)]) #define CC_SELF() CC_CPU(PCPU_GET(cpuid)) #else @@ -287,6 +288,12 @@ for (;;) { cpu = c->c_cpu; +#ifdef SMP + if (cpu == CPUBLOCK) { + cpu_spinwait(); + continue; + } +#endif cc = CC_CPU(cpu); CC_LOCK(cc); if (cpu == c->c_cpu) @@ -593,7 +600,6 @@ */ if (c->c_flags & CALLOUT_LOCAL_ALLOC) cpu = c->c_cpu; -retry: cc = callout_lock(c); if (cc->cc_curr == c) { /* @@ -625,15 +631,19 @@ cancelled = 1; c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING); } +#ifdef SMP /* - * If the lock must migrate we have to check the state again as - * we can't hold both the new and old locks simultaneously. + * If the lock must migrate we have to block the callout locking + * until migration is completed. */ if (c->c_cpu != cpu) { + c->c_cpu = CPUBLOCK; + CC_UNLOCK(cc); + cc = CC_CPU(cpu); + CC_LOCK(cc); c->c_cpu = cpu; - CC_UNLOCK(cc); - goto retry; } +#endif if (to_ticks <= 0) to_ticks = 1;