DF-5681 / fix.diff
--- a/sys/libprop/prop_number.c +++ b/sys/libprop/prop_number.c @@ -164,10 +164,27 @@ static const rb_tree_ops_t _prop_number_rb_tree_ops = { static struct rb_tree _prop_number_tree; _PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex) +static int _prop_number_init(void); + /* ARGSUSED */ static _prop_object_free_rv_t _prop_number_free(prop_stack_t stack, prop_object_t *obj) { @@ -176,6 +193,23 @@ _prop_number_free(prop_stack_t stack, prop_object_t *obj) _PROP_ONCE_DECL(_prop_number_init_once) +/* + * Complete the lazy initialization single-threaded at the same SYSINIT + * point that already creates the number objcache pool + * (_PROP_POOL_INIT, prop_object_impl.h:273-281 — SI_SUB_PROP). The + * kernel flavor of _PROP_ONCE_RUN (prop_object_impl.h:302-303) is a + * cmpset-once with no completion barrier: a CPU that loses the cmpset + * proceeds immediately and can reach lockmgr()/_prop_rb_tree_find() + * while the winner is still inside _prop_number_init() — lockinit() + * then wipes the loser's acquisition (kern_lock.c:1300-1307) and the + * tree's rbt_ops may still be NULL (prop_rb.c:90-93). Any first use + * necessarily comes after SI_SUB_PROP because the objcache pool the + * alloc path needs is itself created at SI_SUB_PROP, so this bootstrap + * closes the window without adding a spin/wait to the hot path. + */ +static void +_prop_number_bootstrap(void *unused __unused) +{ + _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init); +} + +SYSINIT(prop_number, SI_SUB_PROP, SI_ORDER_ANY, + (sysinit_cfunc_t)_prop_number_bootstrap, NULL); + static int _prop_number_init(void) { |