summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-22 11:45:59 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-22 11:45:59 -0400
commit349ee341539a0c1e9e3be11563251589eb42f8a8 (patch)
treef85e8595c474c3ffad23ecfb3dbfd1be579c7dd0 /kernel/gsp_sema_service.c
parent70ab7b57af31cc022775d45634ab828fce43eb1d (diff)
downloadopen-iov-349ee341539a0c1e9e3be11563251589eb42f8a8.tar.gz
open-iov-349ee341539a0c1e9e3be11563251589eb42f8a8.zip
r469 THE streams_events staging-reuse corruption root cause: a GR entry whose push content is implausible (unwritten / previous-epoch page, no QMD word seen) was consumed as a no-op and the end-of-pass counter publish then advanced the guest's completion word while the real push had never been read - the client drained a staging buffer that still held the PREVIOUS copy's bytes (probe run: BUF s=2 got=c0's 0,0.75,1.5.. instead of c2's 3.0,5.25,7.5..; log: 'pub-adv h=0x5c000062 val=4 cur=1' at 210741.947, 4.5 s before the c2 D2H copy executed at 210746.371, with the ring slots decoded as zero-content pushes at 210736). The implausible-content read now feeds the m164 GR no-capture hold (bounded gsp_sema_gr_nocap_hold_ms window, rehold forces a fresh capture): the entry stays unconsumed, the publish gate (last_get != put) suppresses the early completion, and the retry reads the client's real push once it lands. Plausible fallback reads (validated pin / displaced pair) clear the flag.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 756e644..ec61f4e 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -20717,6 +20717,29 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
pb, len) != 0;
bool injected = false;
bool allow_ops = (ch->engine_type != 0);
+ /*
+ * r469 (streams_events staging-reuse
+ * corruption): the primary read was a
+ * resolved page whose bytes do not parse
+ * as a method stream AND the fallback
+ * reads found nothing better - the page
+ * is (still) the client's unwritten /
+ * previous-epoch buffer. For a GR entry
+ * this must count as "content not yet
+ * written" and feed the no-capture hold:
+ * consuming it as a no-op lets the
+ * end-of-pass counter publish advance the
+ * guest's completion word while the real
+ * push (and its work) has not even been
+ * read, and the client then drains a
+ * staging buffer that still holds the
+ * PREVIOUS copy's bytes (observed: h_c[2]
+ * = c0 because the c2 D2H's completion
+ * word was published 4.5 s before its
+ * copy ran). Cleared when a later
+ * candidate read parses.
+ */
+ bool implausible = false;
/*
* A resolved buffer that does not start
@@ -20743,6 +20766,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
&iap) == 0);
if (!svc_method_stream_plausible(pb, len)) {
svc.false_trans++;
+ implausible = true;
if (injected) {
u8 *fb = kmalloc(len,
GFP_KERNEL);
@@ -20753,6 +20777,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_method_stream_plausible(fb, len)) {
memcpy(pb, fb, len);
injected = false;
+ implausible = false;
svc.pushpg_fallback++;
if (gsp_sema_dbg &&
svc_pushpg_fb_log < 16) {
@@ -20792,6 +20817,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
memcpy(pb, db, len);
injected = false;
unreadable = false;
+ implausible = false;
}
kfree(db);
}
@@ -20815,6 +20841,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
memcpy(pb, db, len);
injected = false;
unreadable = false;
+ implausible = false;
}
kfree(db);
}
@@ -21467,10 +21494,25 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* through to the historical
* consume so the channel can
* never livelock.
+ *
+ * r469: an IMPLAUSIBLE push
+ * (the page does not parse as a
+ * method stream: unwritten or
+ * previous-epoch content) is the
+ * same "not the client's work
+ * yet" condition even though no
+ * QMD word was seen - consuming
+ * it as a no-op let the
+ * end-of-pass counter publish
+ * satisfy the client's wait
+ * before the real push was ever
+ * read (the streams_events
+ * staging-reuse corruption).
*/
if (!ch->engine_type && va && len &&
gsp_phys_gr_forward_enabled() &&
- svc_gr_qmd_seen > 0 &&
+ (svc_gr_qmd_seen > 0 ||
+ implausible) &&
!entry_replay &&
!(svc_gr_cand.valid &&
svc_gr_cand.h_object ==