summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 12:00:52 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 12:10:03 -0400
commit04aad03adc45683d03fe1451b8f234061e6b88ff (patch)
treebd354b50006a57bf54a302ba6a086fdca137f902
parent2658fedd556f872f11dd3aeefa88ff6eb76c5342 (diff)
downloadopen-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.c59
-rw-r--r--kernel/gsp_sema_service.c14
-rw-r--r--kernel/gsp_sema_service.h8
-rw-r--r--kernel/main.c10
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):