From 3b063e2fc846b367b2d782d04ec9588078a3ae26 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Fri, 9 Oct 2026 21:55:10 -0400 Subject: vgsp-sema: hold an entry on ANY failed op, not only an unresolvable operand (ISSUE-0002) r71 c3 reached the pma scrub and froze in scrubCheckAndWaitForSize: three vidmem memsets (1 MiB / 297 KiB / 608 KiB) failed with -EINVAL because svc_op_translate resolved their client-VA destinations through a walk to an out-of-bounds vidmem translation before the scanner pinned the real sysmem pages. Only svc_op_translate's own failure sets op_tr_pending, so the pump consumed the entry and applied the release while the memset work was lost. svc_run_ops now marks the pass op-pending for any op that did not run (rc != 0, rc != SVC_COPY_FORWARDED): the pump holds the entry and withholds its releases (bounded by SVC_OPDEF_HOLD_MS) so the retried decode picks up the injected pin and runs the memset; on expiry the release is flushed and the op stays skipped, exactly like the -ENOENT path. Sessions with no failed ops (c1/c2 were 0 fails in r71) are unaffected. --- kernel/gsp_sema_service.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'kernel') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 075a429..77ae4b4 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -4613,6 +4613,23 @@ static void svc_run_ops(struct nv_vgpu_device *vgpu, struct svc_memset_op *ops, svc.memsets_nomap++; else svc.memsets_fail++; + /* + * ISSUE-0002 (r71): ANY failed op leaves work owed on this + * entry, not only an unresolvable operand. The pma scrub + * memsets resolve a bogus out-of-bounds vidmem destination + * through a walk before the scanner pins the real sysmem + * page; svc_copy fails them with -EINVAL, and the old code + * consumed the entry and applied the release anyway, leaving + * the client frozen in scrubCheckAndWaitForSize. Mark the + * pass as op-pending so the pump holds the entry and + * withholds its releases (bounded by SVC_OPDEF_HOLD_MS, + * exactly like the -ENOENT path): the retried decode checks + * the injected pins first and runs the memset once the real + * translation lands. On expiry the release is flushed and the + * op stays skipped (the pre-r62 fallback). + */ + if (rc != 0 && rc != SVC_COPY_FORWARDED) + svc.op_tr_pending = 1; if (gsp_sema_dbg && m->bytes == 256 && svc.sem256_log < 64) { svc.sem256_log++; pr_info("sema-256: type=%u dst=0x%llx src=0x%llx bytes=%llu rc=%d h=0x%x done=%llu nomap=%llu fail=%llu\n", -- cgit v1.2.3