Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -347,6 +347,14 @@ td->td_state = TDS_INACTIVE; td->td_lastcpu = td->td_oncpu = NOCPU; + /* + * Some architectures require sleepable locks for vtophys, but + * td -> domain resolution can be performed by idle threads which + * make such calls illegal. Work around the problem by resolving + * upfront. + */ + td->td_allocdomain = vm_phys_domain(vtophys(td)); + /* * Note that td_critnest begins life as 1 because the thread is not * running and is thereby implicitly waiting to be on the receiving @@ -544,7 +552,7 @@ struct thread_domain_data *tdd; struct thread *ztd; - tdd = &thread_domain_data[vm_phys_domain(vtophys(td))]; + tdd = &thread_domain_data[td->td_allocdomain]; ztd = atomic_load_ptr(&tdd->tdd_zombies); for (;;) { td->td_zombie = ztd; Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -243,6 +243,7 @@ struct rl_q_entry *td_rlqe; /* (k) Associated range lock entry. */ struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */ lwpid_t td_tid; /* (b) Thread ID. */ + int td_allocdomain; /* (b) NUMA domain backing the object. */ sigqueue_t td_sigqueue; /* (c) Sigs arrived, not delivered. */ #define td_siglist td_sigqueue.sq_signals u_char td_lend_user_pri; /* (t) Lend user pri. */