diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-09 21:44:24 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-09 21:44:24 -0400 |
| commit | 7308a66e2670fc19d411fba1cc7e16569170a76d (patch) | |
| tree | 0c82ecf65546dd0aba8fbb34a0d7f1e2846d4dc7 /kernel | |
| parent | b021abb242664d0c4cb2492c5d73aa7bdcdee4c4 (diff) | |
| download | open-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.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 28 |
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; |
