summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c55
1 files changed, 52 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index b90c948..bcd8ac3 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -6032,6 +6032,24 @@ static void svc_copy_snap_capture(struct nv_vgpu_device *vgpu, u64 dst,
if (svc_copy_snap_lookup(dst, src, total, owner_ch, owner_idx,
owner_hash))
return; /* already captured */
+ /*
+ * r456: evict any snapshot left by the SAME ring slot under a
+ * DIFFERENT push hash (the slot was reused by a fresh push). The
+ * surviving-across-retries snapshot (svc_opdef_clear APPLY no
+ * longer frees it) must never be readable by the next occupant of
+ * the slot; the pass hash changes whenever the guest rewrites the
+ * push, so a same-slot different-hash snapshot is by definition
+ * stale for the new push.
+ */
+ for (i = 0; i < SVC_COPY_SNAP_N; i++) {
+ if (svc_copy_snaps[i].buf &&
+ svc_copy_snaps[i].owner_ch == owner_ch &&
+ svc_copy_snaps[i].owner_idx == owner_idx &&
+ svc_copy_snaps[i].owner_hash != owner_hash) {
+ kfree(svc_copy_snaps[i].buf);
+ svc_copy_snaps[i].buf = NULL;
+ }
+ }
for (i = 0; i < SVC_COPY_SNAP_N; i++) {
if (!svc_copy_snaps[i].buf) {
s = &svc_copy_snaps[i];
@@ -7452,6 +7470,18 @@ svc_wait_done:
*/
if (ops_done && seq < 64 && ((*ops_done >> seq) & 1)) {
svc.ops_once_skipped++;
+ /*
+ * r456: this op already ran in an earlier pass. Any
+ * staging snapshot a later re-decode pass re-captured
+ * for it (the capture sites run on every decode) is
+ * a leak that the r444 APPLY-free used to sweep; with
+ * that free removed (r456 keeps the snapshot alive
+ * across retries) drop it here so it can never serve
+ * a re-push of the ring slot.
+ */
+ if (m->type == 1 && m->bytes <= SVC_COPY_SNAP_MAX)
+ svc_copy_snap_free(m->dst, m->src, m->bytes,
+ ch_h, entry_idx, pass_hash);
continue;
}
@@ -15876,9 +15906,28 @@ static void svc_opdef_clear(struct svc_opdef_ent *e, u32 caller)
e->n ? e->rel[0].va : 0ull,
e->n ? e->rel[0].payload : 0u);
}
- /* r444: the entry is being consumed; no retry can need its
- * staging snapshot any more (see svc_copy_snap_free_owner). */
- if (e->active)
+ /*
+ * r444: the entry is being consumed; no retry can need its
+ * staging snapshot any more (see svc_copy_snap_free_owner).
+ *
+ * r456: EXCEPT on the APPLY path. The apply runs at the head of a
+ * re-decode pass of an entry whose copy is still held for its
+ * operand pins; the pass's own op execution (which consumes the
+ * snapshot on success) follows the apply. Freeing here destroyed
+ * the pipeline-order snapshot before it could ever be read and
+ * the next pass's guard re-capture then read the driver's
+ * REFILLED ping-pong staging - the r455 operand-shift: the a1 H2D
+ * executed ~3 s after its push with a2's bytes (owner
+ * 0x5c00005c/0/6076682fa76b8792, snapshot first4 flipped from
+ * 00000000 3f000000... to 00000000 3e000000... across retries;
+ * dst16_after=000000000000003e0000803e0000c03e proves the a2
+ * pattern landed in da1's page). The snapshot now survives the
+ * retries and is consumed (and freed) by the copy that finally
+ * executes; svc_copy_snap_free_owner still runs on every genuine
+ * consume path (FINISH/FLUSH/DROP/STALE/COUNTED/SWEEP/STOP) and
+ * the TTL covers the rest.
+ */
+ if (e->active && caller != SVC_OPDEF_CLR_APPLY)
svc_copy_snap_free_owner(e->h_object, e->entry_idx);
memset(e, 0, sizeof(*e));
}