From e756d4fad97a6768f83f8e84d62a26673e0b37f3 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 22 Oct 2026 23:53:31 -0400 Subject: r507a op-failure latch is time-based: a full opdef window before it stops holding (r507 matmul lost a pin-late 1 MB UVA copy and verified FAIL) r506w's attempt-count latch tripped after 8 fast passes (~100 ms) while the legitimate pin-late retry needs 0.5-2 s (r507 witness: memcopy dst=0x71365ee02200 src=0x71365e500000 bytes=1048576 rc=-2 skipped; matmul completed with STATUS FAIL instead of hang). The first failure of a VA now arms a full 10000 ms window during which the op holds its entry exactly as before; only after a full bound with no success does the op stop forcing the hold. A success clears the record (fresh window on a later failure). --- kernel/gsp_sema_service.c | 67 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 83bae47..4c46bf3 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -7528,27 +7528,49 @@ static struct svc_wait_hold *svc_wait_hold_get(u32 h, bool create) } /* - * r506w: bounded per-VA failure latch for virtual ops. A virtual op that - * keeps failing -ENOENT (an unresolvable VA) re-runs on every decode pass - * and sets svc.op_tr_pending each time, so its push holds for the full + * r506w/r507a: bounded per-VA failure latch for virtual ops. A virtual op + * that keeps failing -ENOENT (an unresolvable VA) re-runs on every decode + * pass and sets svc.op_tr_pending each time, so its push holds for the full * SVC_OPDEF_HOLD_MS opdef bound - a client whose stream carries such an op * (r505/r506 witness: the RM's channel-progress zeroing at 0x2000c0xxx * after the first client, dst never translated) ground its whole stream * at ~10 s per push ("hang after DEVICE" for matmul/multikernel). - * After SVC_OPFAIL_LATCH failures of the same VA the op still attempts - * the write but no longer forces the hold: the entry consumes promptly and - * its withheld release is applied, exactly the outcome the expired bound + * + * The window must still cover the legitimate pin-late retry (observed + * pin latency 0.5-2 s: the H2D copy's operands land a moment after the + * push, r507 matmul's 1 MB UVA copy at 0x7136... needed >8 fast passes), + * so the latch is TIME-based: the FIRST failure of a VA arms a + * SVC_OPDEF_HOLD_MS window during which the op holds its entry exactly as + * before; after a full bound with no success the op still attempts the + * write but no longer forces the hold - the entry consumes promptly and + * its withheld release applies, exactly the outcome the expired bound * already sanctioned (op stays skipped, release delivered), minus the - * 10 s tax per pass. Service-thread only, like every other op path. + * 10 s tax per subsequent pass. A success clears the record (a later + * failure gets a fresh window). Service-thread only, like every other op + * path. + */ +#define SVC_OPFAIL_MAX 32 +/* + * r507a: the op-failure window rides the opdef hold bound (10000 ms, + * SVC_OPDEF_HOLD_MS defined further down). Keep the literal here so the + * latch (used by svc_run_ops) precedes that define. */ -#define SVC_OPFAIL_LATCH 8 -#define SVC_OPFAIL_MAX 16 +#define SVC_OPFAIL_WINDOW_MS 10000u static struct { u64 va; - u32 n; + unsigned long since; } svc_opfail[SVC_OPFAIL_MAX]; static u32 svc_opfail_log; +static void svc_opfail_clear(u64 va) +{ + u32 i; + + for (i = 0; i < SVC_OPFAIL_MAX; i++) + if (svc_opfail[i].va == va) + svc_opfail[i].va = 0; +} + static bool svc_opfail_latched(u64 va) { u32 i; @@ -7556,21 +7578,24 @@ static bool svc_opfail_latched(u64 va) for (i = 0; i < SVC_OPFAIL_MAX; i++) { if (svc_opfail[i].va == va) { - svc_opfail[i].n++; - if (svc_opfail[i].n == SVC_OPFAIL_LATCH && - svc_opfail_log < 32) { - svc_opfail_log++; - pr_info("sema-svc: OPFAIL-LATCH va=0x%llx n=%u (op no longer holds its entry)\n", - va, svc_opfail[i].n); + if (time_after_eq(jiffies, + svc_opfail[i].since + + msecs_to_jiffies(SVC_OPFAIL_WINDOW_MS))) { + if (svc_opfail_log < 32) { + svc_opfail_log++; + pr_info("sema-svc: OPFAIL-LATCH va=0x%llx (>=%u ms of failures; op no longer holds its entry)\n", + va, SVC_OPFAIL_WINDOW_MS); + } + return true; } - return svc_opfail[i].n >= SVC_OPFAIL_LATCH; + return false; } if (!svc_opfail[i].va && free_i == SVC_OPFAIL_MAX) free_i = i; } if (free_i < SVC_OPFAIL_MAX) { svc_opfail[free_i].va = va; - svc_opfail[free_i].n = 1; + svc_opfail[free_i].since = jiffies; } return false; } @@ -7832,9 +7857,11 @@ svc_wait_done: */ if (rc == SVC_COPY_FORWARDED) continue; - if (rc == 0) + if (rc == 0) { svc.memsets_done++; - else if (rc == -ENOENT) + /* r507a: a success re-arms the failure window. */ + svc_opfail_clear(m->dst); + } else if (rc == -ENOENT) svc.memsets_nomap++; else svc.memsets_fail++; -- cgit v1.2.3