DF-2850 / fix.diff
--- sys/kern/subr_gtaskqueue.c 2026-06-29 12:51:19.000000000 +0000 +++ /tmp/opencode/v26/fixtree/sys/kern/subr_gtaskqueue.c 2026-10-24 16:33:07.789715562 +0000 @@ -70,6 +70,7 @@ struct thread **tq_threads; int tq_tcount; int tq_flags; + int tq_first_error; /* DF-2850 */ #if 0 taskqueue_callback_fn tq_callbacks[TASKQUEUE_NUM_CALLBACKS]; void *tq_cb_contexts[TASKQUEUE_NUM_CALLBACKS]; @@ -453,13 +454,26 @@ "%s_%d", ktname, i); } if (error) { - /* should be ok to continue, taskqueue_free will dtrt */ + /* + * DF-2850: remember the failure; if NO thread was + * created the queue can never run anything and + * every future drain would sleep forever - tear + * the partial state down and report the error + * instead of silently returning success. + */ kprintf("%s: lwkt_create(%s): error %d", __func__, ktname, error); - tq->tq_threads[i] = NULL; /* paranoid */ + tq->tq_threads[i] = NULL; + if (tq->tq_first_error == 0) + tq->tq_first_error = error; } else tq->tq_tcount++; } + if (tq->tq_tcount == 0 && tq->tq_first_error) { + kfree(tq->tq_threads, M_GTASKQUEUE); + tq->tq_threads = NULL; + return (tq->tq_first_error); + } for (i = 0; i < count; i++) { if (tq->tq_threads[i] == NULL) continue; |