DF-2814 / fix.diff
--- sys/kern/kern_objcache.c 2026-06-29 12:51:19.000000000 +0000 +++ /tmp/opencode/v26/fixtree/sys/kern/kern_objcache.c 2026-10-24 16:33:07.789715562 +0000 @@ -149,6 +149,8 @@ struct objcache_desc *desc; + int oc_dying; /* DF-2814 */ + /* NUMA-cluster level caches */ struct magazinedepot depot[MAXCLUSTERS]; @@ -432,6 +434,12 @@ void *obj; struct magazinedepot *depot; + /* + * DF-2814: refuse allocations from a cache being destroyed. + */ + if (oc->oc_dying) + return (NULL); + KKASSERT((ocflags & M_ZERO) == 0); crit_enter(); ++cpucache->gets_cumulative; @@ -623,6 +631,17 @@ struct magazine *loadedmag; struct magazinedepot *depot; + /* + * DF-2814: a cache being destroyed may still receive puts from + * in-flight users; dispose directly instead of touching freed + * magazines. + */ + if (oc->oc_dying) { + oc->dtor(obj, oc->privdata); + oc->free(obj, oc->allocator_args); + return; + } + crit_enter(); ++cpucache->puts_cumulative; @@ -902,6 +921,15 @@ } /* + * DF-2814: no-op IPI used as a cross-cpu barrier during destroy. + */ +static void +objcache_noop_ipi(void *arg __unused, int arg2 __unused, + struct intrframe *frame __unused) +{ +} + +/* * Destroy an object cache. Must have no existing references. */ void @@ -917,6 +945,27 @@ LIST_REMOVE(desc, next); spin_unlock(&objcachelist_spin); + /* + * DF-2814: mark the cache dying, then barrier against every cpu + * so in-flight get/put operations have completed before we rip + * the per-cpu magazines out from under them. The per-cpu + * magazine contract is crit_enter protection on the OWNING cpu; + * an IPI only executes outside a critical section, so after the + * synchronize no cpu can hold a stale magazine reference. + */ + oc->oc_dying = 1; + cpu_sfence(); + { + int bcpu; + for (bcpu = 0; bcpu < ncpus; ++bcpu) { + if (globaldata_find(bcpu) == mycpu) + continue; + lwkt_send_ipiq3(globaldata_find(bcpu), + objcache_noop_ipi, NULL, 0); + } + lwkt_synchronize_ipiqs("objcache_destroy"); + } + SLIST_INIT(&tmplist); for (clusterid = 0; clusterid < MAXCLUSTERS; clusterid++) { depot = &oc->depot[clusterid]; |