summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 21:44:24 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 21:44:24 -0400
commit7308a66e2670fc19d411fba1cc7e16569170a76d (patch)
tree0c82ecf65546dd0aba8fbb34a0d7f1e2846d4dc7
parentb021abb242664d0c4cb2492c5d73aa7bdcdee4c4 (diff)
downloadopen-iov-7308a66e2670fc19d411fba1cc7e16569170a76d.tar.gz
open-iov-7308a66e2670fc19d411fba1cc7e16569170a76d.zip
vgsp-sema: gate the pool-residue rule on the first translated pool read, not submissions (ISSUE-0002)
r70 c3 proved the submissions gate wrong: the content-rescue path consumes entry 0 (submissions++) while the pool page is still untranslated (rrc=-2), then the scanner's pin batch rewinds last_get (SVC_PIN_REWIND) and the entry is decoded again - this time with cur=134 residue, pay=1, but submissions already 1, so the residue branch was skipped, the hold branch deferred the release, and the pending retry dropped it (payload <= cur). The client's first tracker wait then never completed. Replace the freshness gate with a per-channel pool_rel_seen flag set on the first translated pool read (rrc2 == 0), persisted in the pump write-back. The residue rule now fires exactly on that first read, exactly once per channel per session.
-rw-r--r--kernel/gsp_sema_service.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index d69be19..075a429 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -168,6 +168,18 @@ struct svc_channel {
* last_get to slot 0 so the live first push is
* processed instead of skipped. */
bool logged; /* one state log per channel */
+ bool pool_rel_seen; /* ISSUE-0002 r70: a pool release word for
+ * this channel has been read through a
+ * translated source at least once in this
+ * session. The residue rule (first release of
+ * a fresh channel whose word reads far ahead
+ * of the payload) must fire on the FIRST
+ * translated read only: the rescue path can
+ * consume entry 0 (submissions++) before the
+ * pool pin lands, the pin batch then rewinds
+ * last_get, and the re-decode is no longer a
+ * fresh channel by submissions - but it still
+ * is by this flag. */
u64 instance_pa;
u64 notifier_pa; /* error notifier: NvNotification slots */
u32 notifier_as;
@@ -6504,7 +6516,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
SEM_REDUCTION_INC) ? 1 : 0);
} else if (svc_pool_sem_va(sem_va) &&
ch && ch->engine_type &&
- !ch->submissions &&
+ !ch->pool_rel_seen &&
cur > st.sem_payload) {
/*
* ISSUE-0002 (r63/r64): the
@@ -6589,6 +6601,19 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (st.sem_payload > cur)
pending = 1;
}
+ /*
+ * ISSUE-0002 r70: the residue rule
+ * applies to the first translated
+ * pool read of the session only.
+ * The rescue path can consume entry 0
+ * before the pool pin lands and the
+ * pin batch then rewinds last_get,
+ * so a submissions-based freshness
+ * test misses the re-decode; this
+ * flag does not.
+ */
+ if (!rrc2 && svc_pool_sem_va(sem_va) && ch)
+ ch->pool_rel_seen = true;
}
/*
@@ -14359,6 +14384,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
bitmap_copy(svc.chan[k].rel_done, ch->rel_done,
SVC_GPFIFO_MAX_BITS);
svc.chan[k].last_rel_va = ch->last_rel_va;
+ svc.chan[k].pool_rel_seen = ch->pool_rel_seen;
svc.chan[k].rescue_last = ch->rescue_last;
svc.chan[k].rescue_fail = ch->rescue_fail;
svc.chan[k].push_hold_until = ch->push_hold_until;