DF-5839 / fix.diff
--- a/sys/kern/lwkt_thread.c +++ b/sys/kern/lwkt_thread.c @@ -366,6 +366,25 @@ KKASSERT((td->td_flags & (TDF_RUNNING|TDF_PREEMPT_LOCK| TDF_RUNQ)) == 0); gd->gd_freetd = NULL; + /* + * A foreign-cpu lwkt_hold() can land in the gd_freetd + * publication window of lwkt_exit() (the per-cpu critical + * section cannot exclude cross-cpu atomics), leaving a + * published corpse with td_refs != 0. Never rebirth such + * a corpse: lwkt_init_thread()'s bzero would wipe the live + * refcount and the stale lwkt_rele() would then decrement + * the recycled thread's td_refs to -1 (permanent exit + * livelock on stock kernels). Dropping the corpse leaks + * its cached kstack, which is safe: the holder still owns + * the pointer. + */ + if (td->td_refs) { + kprintf("lwkt_alloc_thread: freetd corpse %p still has " + "%d refs, dropping\n", td, td->td_refs); + td = objcache_get(thread_cache, M_WAITOK); + KKASSERT((td->td_flags & (TDF_RUNNING|TDF_PREEMPT_LOCK| + TDF_RUNQ)) == 0); + } } else { td = objcache_get(thread_cache, M_WAITOK); KKASSERT((td->td_flags & (TDF_RUNNING|TDF_PREEMPT_LOCK| |