diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-18 12:00:52 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-18 12:10:03 -0400 |
| commit | 04aad03adc45683d03fe1451b8f234061e6b88ff (patch) | |
| tree | bd354b50006a57bf54a302ba6a086fdca137f902 | |
| parent | 2658fedd556f872f11dd3aeefa88ff6eb76c5342 (diff) | |
| download | open-iov-04aad03adc45683d03fe1451b8f234061e6b88ff.tar.gz open-iov-04aad03adc45683d03fe1451b8f234061e6b88ff.zip | |
vgsp: fail4 discrimination tooling - copy-out page witnesses + full-boot bigcopy resolution budget
Four guest CUDA clients fail all-bad while four pass; the aggregate
counters cannot separate 'engine result never produced' from 'produced
but written to a different guest page than the client's read resolves'.
Add the two per-page witnesses that correlate the write side with the
read side:
- gsp_phys_gr_copyout_dump (booter, default 1): per-changed-page
OUT-PAGE-WIT va=<device VA> hpa=<guest PA written> first8/last8=<bytes
shipped>, bounded 12 pages per launch, plus one RELOC-CENSUS line per
launch (gaps vs late-resolved words vs late pages).
- sema_bigcopy_log (sema service, default 24, was a hardcoded per-boot
budget): the svc_copy large-copy proof already logs both operands'
resolved VA -> pa/aperture/provenance and the first 16 bytes each side;
raising the budget past the boot's head makes the failing clients'
H2D/D2H resolutions visible.
Discrimination test for the next cycle: same device VA on OUT-PAGE-WIT
(copy-out HPA) and sema-bigcopy (D2H source pa) with different PAs proves
the produced-but-misplaced class; equal PAs redirects to the readback
content/engine-input path.
(cherry picked from commit 78ea8b7807231ac418a17b85c29ed1845e1b0062)
| -rw-r--r-- | kernel/gsp_phys_booter.c | 59 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 14 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.h | 8 | ||||
| -rw-r--r-- | kernel/main.c | 10 |
4 files changed, 90 insertions, 1 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 6a66a16..2f74fa1 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -116,6 +116,30 @@ module_param_named(gsp_phys_gr_reloc_resolve, gsp_phys_gr_reloc_resolve_param, MODULE_PARM_DESC(gsp_phys_gr_reloc_resolve, "Resolve QMD words that match no tracked data page and author them as late data pages (default 1: RELOC-FIXED; 0: RELOC-GAP only)"); +/* + * COPYWIT (2026-10-18 fail4 discrimination tooling, default 1): witness the + * copy-out of every tracked page the engine changed - device VA, guest HPA + * the results were written back to, and the first/last 8 bytes actually + * shipped. Correlating these lines with the sema-bigcopy D2H resolution lines + * (same VA -> pa) and the client's own check discriminates "engine result + * never produced" from "produced but landed on a different guest page than + * the client's read resolves" - the two classes the all-bad client results + * cannot separate from the aggregate counters alone. Bounded per launch + * (GSP_PHYS_GR_COPYWIT_MAX) and rate-limited; 0 disables both this and the + * per-launch RELOC-CENSUS line. + */ +#define GSP_PHYS_GR_COPYWIT_MAX 12u +static bool gsp_phys_gr_copyout_dump_param = true; +module_param_named(gsp_phys_gr_copyout_dump, gsp_phys_gr_copyout_dump_param, + bool, 0644); +MODULE_PARM_DESC(gsp_phys_gr_copyout_dump, + "Log per-changed-page copy-out witnesses (VA, HPA, first/last 8 bytes) and the per-launch relocation census (default 1)"); + +static inline bool gsp_phys_gr_copywit_enabled(void) +{ + return READ_ONCE(gsp_phys_gr_copyout_dump_param); +} + bool gsp_phys_boot_enabled(void) { return gsp_phys_boot_param; @@ -19124,6 +19148,19 @@ gr_page_unmapped: ret = -EAGAIN; goto out; } + /* + * COPYWIT fail4: one per-launch census of the rewrite outcome so the + * resolved/unresolved split of every bank pass is provable from a + * single line (gaps left as guest VAs vs late-resolved words authored + * via RELOC-FIXED). Rate-limited like the per-word lines. + */ + if (gsp_phys_gr_copywit_enabled() && + (reloc_gap || gsp_phys_gr_reloc_fixed)) + pr_info_ratelimited("vgsp-gr: RELOC-CENSUS gaps=%u first_gap=0x%llx fixed=%llu first_fixed=0x%llx late_pages=%u\n", + reloc_gap, reloc_gap_first, + gsp_phys_gr_reloc_fixed, + gsp_phys_gr_reloc_fixed_first, + gsp_phys_gr_gap_n); /* * Rank-2 qmdwin (gsp_phys_rmcall_gr_qmdwin=1): relocate the inline-QMD @@ -20545,6 +20582,7 @@ gr_page_unmapped: struct gsp_phys_boot_chunk *dchunk = gsp_phys_gr_data_chunk(); u32 wbi, wrote = 0, changed = 0; u32 chg[8] = { }; + u32 outwit = 0; /* COPYWIT: bounded per-launch witness lines */ for (wbi = 0; wbi < req->n_data; wbi++) { u32 bi = gsp_phys_gr_data_bi(req->data[wbi].reloc_va); @@ -20576,6 +20614,27 @@ gr_page_unmapped: get_unaligned_le32(src + 4), get_unaligned_le32(src + 8), get_unaligned_le32(src + 12)); + /* + * COPYWIT fail4: per-changed-page copy-out + * witness - the exact (device VA -> guest + * HPA) pair the results were written back to + * plus the first/last 8 bytes shipped. The + * D2H side of the same VA is named by the + * sema-bigcopy resolution lines; equal VAs + * with different PAs on the two sides is the + * produced-but-misplaced class. + */ + if (gsp_phys_gr_copywit_enabled() && + outwit < GSP_PHYS_GR_COPYWIT_MAX) { + outwit++; + pr_info("vgsp-gr: OUT-PAGE-WIT va=0x%llx hpa=0x%llx bi=%u first8=%016llx last8=%016llx\n", + req->data[wbi].va, + req->data[wbi].hpa, bi, + (u64)get_unaligned_le64(src), + (u64)get_unaligned_le64( + src + GSP_PHYS_PAGE_SIZE - + 8)); + } if (changed < 8) chg[changed] = bi; changed++; diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index fb00685..b354437 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -5265,7 +5265,8 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, * these copies; this separates a wrong resolution from a wrong copy. */ if ((total >= (1u << 20) || - (dst_virt && dst_orig >= SVC_VAS_FLOOR)) && bigcopy_log < 24) { + (dst_virt && dst_orig >= SVC_VAS_FLOOR)) && + bigcopy_log < gsp_sema_bigcopy_log_max) { u8 sb[16] = {0}, db[16] = {0}; bigcopy_log++; @@ -10838,6 +10839,17 @@ bool gsp_sema_copy_dst_pin_guard = 1; * just-built client table is fresh), logged loudly. */ unsigned gsp_sema_copy_dst_guard_ms = 3000; + +/* + * COPYWIT fail4: per-boot budget for the sema-bigcopy resolution witnesses + * (svc_copy's large-copy proof: both operands' VA -> pa/aperture/provenance + * plus the first 16 bytes each side). The shipped default kept the boot's + * head only; a failing-client run happens minutes later, so the budget is a + * module parameter now - raise it for a discrimination cycle and correlate + * each D2H's resolved source PA with the booter's OUT-PAGE-WIT copy-out PA + * for the same device VA. 0 disables the lines. + */ +unsigned gsp_sema_bigcopy_log_max = 24; #define SVC_DST_GUARD_SLOTS 16 struct svc_dst_guard { u64 va_page; diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h index 95f9a4e..4c9042a 100644 --- a/kernel/gsp_sema_service.h +++ b/kernel/gsp_sema_service.h @@ -304,6 +304,14 @@ extern bool gsp_sema_pool_hold_fresh; extern bool gsp_sema_copy_dst_pin_guard; /* + * COPYWIT fail4: per-boot line budget for the sema-bigcopy resolution + * witnesses (svc_copy's large-copy VA -> pa proof). Raise it for a + * discrimination cycle so the failing clients' H2D/D2H resolutions are + * visible; 0 disables the lines. + */ +extern unsigned gsp_sema_bigcopy_log_max; + +/* * F1-b: authorship gate for the GR completion release the forwarded launch's * poll waits on. When on (default), a RAM-sweep release whose VA equals the * in-flight forward request's gr_rel_va is deferred (skipped, not applied) diff --git a/kernel/main.c b/kernel/main.c index bda4f97..52bd10a 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -2827,6 +2827,16 @@ module_param_named(sema_copy_dst_pin_guard, gsp_sema_copy_dst_pin_guard, bool, 0 MODULE_PARM_DESC(sema_copy_dst_pin_guard, "hold device-dst copies without a pin-resolved translation (default 1)"); /* + * COPYWIT fail4 (2026-10-18): per-boot budget for the sema-bigcopy resolution + * witnesses. svc_copy's large-copy proof logs both operands' resolved + * VA -> pa/aperture/provenance, which is the read side of the client data + * path; raise this for a failing-client discrimination cycle so the lines + * survive past the boot's head. 0 disables. + */ +module_param_named(sema_bigcopy_log, gsp_sema_bigcopy_log_max, uint, 0644); +MODULE_PARM_DESC(sema_bigcopy_log, "sema-bigcopy resolution witness budget per boot (default 24; 0 disables)"); + +/* * Debug: inject a verified {GPU VA -> guest PA} translation into the * semaphore service (used when the client's mapping cannot be discovered * from guest structures): |
