DF-2833 / fix.diff
--- sys/kern/vfs_sync.c 2026-06-29 12:51:19.000000000 +0000 +++ /tmp/opencode/v26/fixtree/sys/kern/vfs_sync.c 2026-10-24 16:33:07.789715562 +0000 @@ -93,8 +93,31 @@ SYSCTL_INT(_kern, OID_AUTO, metadelay, CTLFLAG_RW, &metadelay, 0, "VFS metadata synchronization delay"); time_t retrydelay = 1; /* retry delay after failure */ -SYSCTL_INT(_kern, OID_AUTO, retrydelay, CTLFLAG_RW, - &retrydelay, 0, "VFS retry synchronization delay"); + +static int +sysctl_kern_retrydelay(SYSCTL_HANDLER_ARGS) /* DF-2833 */ +{ + int error; + int v = retrydelay; + + error = sysctl_handle_int(oidp, &v, 0, req); + if (error || !req->newptr) + return (error); + /* + * retrydelay <= 0 requeues drained vnodes into the bucket being + * drained (vn_syncer_add slot == syncer_delayno) and livelocks + * the syncer while it holds sc_token. + */ + if (v < 1) + v = 1; + retrydelay = v; + + return(0); +} + +SYSCTL_PROC(_kern, OID_AUTO, retrydelay, CTLTYPE_INT | CTLFLAG_RW, + 0, 0, sysctl_kern_retrydelay, "I", + "VFS retry synchronization delay"); static int rushjob; /* number of slots to run ASAP */ static int stat_rush_requests; /* number of times I/O speeded up */ SYSCTL_INT(_debug, OID_AUTO, rush_requests, CTLFLAG_RW, @@ -132,8 +155,8 @@ return (error); if (v < 1) v = 1; - if (v > SYNCER_MAXDELAY) - v = SYNCER_MAXDELAY; + if (v > SYNCER_MAXDELAY - 2) + v = SYNCER_MAXDELAY - 2; syncdelay = v; return(0); @@ -205,7 +228,15 @@ --ctx->syncer_count; } if (delay <= 0) { - slot = -delay & ctx->syncer_mask; + /* + * DF-2833: never requeue into the bucket currently being + * drained - that livelocks the syncer drain loop while it + * holds sc_token. + */ + slot = (ctx->syncer_delayno + (-delay ? -delay : 1)) & + ctx->syncer_mask; + if (slot == (ctx->syncer_delayno & ctx->syncer_mask)) + slot = (ctx->syncer_delayno + 1) & ctx->syncer_mask; } else { if (delay > SYNCER_MAXDELAY - 2) delay = SYNCER_MAXDELAY - 2; |