summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 15:30:23 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 15:30:38 -0400
commit54a41db23985a82654ad4daeca283682e2b14b1e (patch)
tree0a641ab0418301f3c17085b4d2dc060d7ce0bfc9
parent970ca73e82917c30d8ca2dfd24b10fff552900be (diff)
downloadopen-iov-54a41db23985a82654ad4daeca283682e2b14b1e.tar.gz
open-iov-54a41db23985a82654ad4daeca283682e2b14b1e.zip
vgsp: fail4 r231 - READ-ORDER guard/witness + 32KB copy-resolution witness
r231 probe: RAWA (fresh 64 KB upload -> straight D2H readback, no kernel) returned foreign deterministic content (0x437F0000-family ramps) where the uploaded ints 0..16383 must be, and PROBE2 == PROBE2B on that same content. The upload/readback round trip inside the emulation is therefore not content-preserving - before any engine execution. Two candidate mechanisms, both now witnessed: - READ-ORDER: a device-src copy reading a VA whose device-dst write is still inside the m169 pin-guard window (the writer's bytes land only when the guard resolves) - the read executes first. READ-ORDER-WIT logs the coincidence; with sema_read_order_guard=1 (new param, default 0) the read is deferred through the existing bounded-hold re-decode so it runs after the write. Opt-in pending an A/B proving no green regression. - RESOLUTION DIVERGENCE: the dst (H2D) resolution consults the ledger before svc_op_translate while the src (D2H) resolution does the opposite, so a stale ledger landing can make the writer and reader touch different pages. The sema-bigcopy proof (va->pa/aperture/provenance for BOTH sides) now fires from 32 KB (was 1 MB), so the probe-class copies are on record. Build green; module param registered and visible. (cherry picked from commit bfe5d295dd3922c0dbcd0bd1a29912a02acb58ec)
-rw-r--r--kernel/gsp_sema_service.c57
-rw-r--r--kernel/gsp_sema_service.h7
-rw-r--r--kernel/main.c10
3 files changed, 73 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index e57bcac..9de9038 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3104,6 +3104,8 @@ static inline bool svc_pool_pa_identity(u64 va, u64 pa)
static void svc_pool_boot_store(u64 va, u64 pa, int ap); /* m168 */
static bool svc_dst_guard_hold(u64 va); /* m169b */
+static bool svc_dst_guard_pending(u64 va); /* r231 */
+static u32 svc_read_order_log; /* r231 budget */
static int svc_pool_pa_lookup(u64 va, u64 *pa, int *ap)
{
@@ -5241,6 +5243,24 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
dst_orig, dst_prov);
return -ENOENT;
}
+ /*
+ * r231 READ-ORDER guard/witness: a device-src copy whose source VA
+ * has a PENDING device-dst write hold reads the PRE-write content -
+ * the writer's bytes land only when the guard resolves while the
+ * reader executes immediately (the ctaid_probe RAWA round trip is
+ * the reproducer). Witnessed always (bounded); deferred only with
+ * sema_read_order_guard, through the same bounded-hold re-decode.
+ */
+ if (src_orig >= SVC_VAS_FLOOR && svc_dst_guard_pending(src_orig)) {
+ if (svc_read_order_log < 16) {
+ svc_read_order_log++;
+ pr_info("sema-svc: READ-ORDER-WIT device-src copy va=0x%llx reads while a device-dst write to the same VA is still held%s\n",
+ src_orig, gsp_sema_read_order_guard ?
+ " (deferring)" : " (guard off)");
+ }
+ if (gsp_sema_read_order_guard)
+ return -ENOENT;
+ }
if (!src_phys) {
u64 pa;
u32 aper;
@@ -5285,7 +5305,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
* 16 bytes on each side before the copy. The vadd data path is exactly
* these copies; this separates a wrong resolution from a wrong copy.
*/
- if ((total >= (1u << 20) ||
+ if ((total >= SVC_COPY_AUDIT_MIN ||
(dst_virt && dst_orig >= SVC_VAS_FLOOR)) &&
bigcopy_log < gsp_sema_bigcopy_log_max) {
u8 sb[16] = {0}, db[16] = {0};
@@ -10862,6 +10882,21 @@ bool gsp_sema_copy_dst_pin_guard = 1;
unsigned gsp_sema_copy_dst_guard_ms = 3000;
/*
+ * r231 READ-ORDER guard (default 0: witness only). A device-src copy whose
+ * source VA has a PENDING device-dst write hold (the m169 guard window is
+ * still open) reads the PRE-write content: the writer's bytes land only
+ * when the guard resolves, while the reader can execute immediately. The
+ * ctaid_probe RAWA round trip is the reproducer - upload a fresh 64 KB
+ * buffer, read it straight back with no kernel - and the readback came
+ * back as foreign deterministic content. With this on, such a read is
+ * deferred through the existing bounded-hold machinery (-ENOENT) so it
+ * re-decodes after the write resolves; with it off the condition is
+ * logged (READ-ORDER-WIT) so the next capture proves the coincidence.
+ * Opt-in until an A/B proves no green regression.
+ */
+bool gsp_sema_read_order_guard;
+
+/*
* 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
@@ -10911,6 +10946,26 @@ static bool svc_dst_guard_hold(u64 va)
}
/*
+ * r231 READ-ORDER guard: true while a held device-dst write for this VA
+ * page is still inside its bounded window (the writer's bytes have not
+ * landed yet). See the gsp_sema_read_order_guard declaration.
+ */
+static bool svc_dst_guard_pending(u64 va)
+{
+ u64 page = va & ~(u64)(SEMA_PAGE_SIZE - 1);
+ unsigned long now = jiffies;
+ u32 i;
+
+ for (i = 0; i < SVC_DST_GUARD_SLOTS; i++)
+ if (svc_dst_guard[i].va_page == page &&
+ svc_dst_guard[i].first &&
+ time_before(now, svc_dst_guard[i].first +
+ msecs_to_jiffies(gsp_sema_copy_dst_guard_ms)))
+ return true;
+ return false;
+}
+
+/*
* CE release fallback: when a push carrying a tracking-semaphore release
* cannot be read (and the content rescue failed), advance the channel's
* tracking semaphore to the expected payload directly. The push's data
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index 4c9042a..55d323c 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -304,6 +304,13 @@ extern bool gsp_sema_pool_hold_fresh;
extern bool gsp_sema_copy_dst_pin_guard;
/*
+ * r231 READ-ORDER guard (default 0: witness only). Defer a device-src copy
+ * whose source VA has a pending device-dst write hold (READ-ORDER-WIT) so
+ * the read re-decodes after the write resolves. Opt-in pending an A/B.
+ */
+extern bool gsp_sema_read_order_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
diff --git a/kernel/main.c b/kernel/main.c
index 52bd10a..c150a1a 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)");
/*
+ * r231 READ-ORDER guard: defer a device-src copy whose source VA has a
+ * pending device-dst write hold so the read re-decodes after the write
+ * resolves (fixes the ctaid_probe RAWA upload/readback inversion).
+ * Default 0: witness only (READ-ORDER-WIT). Opt-in pending an A/B proving
+ * no green regression.
+ */
+module_param_named(sema_read_order_guard, gsp_sema_read_order_guard, bool, 0644);
+MODULE_PARM_DESC(sema_read_order_guard, "defer device-src reads of a VA with a pending held device-dst write (default 0: witness only)");
+
+/*
* 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