<feed xmlns='http://www.w3.org/2005/Atom'>
<title>open-iov.git/kernel/gsp_sema_service.c, branch lottery-m156-gate-attempt</title>
<subtitle>Open-IOV vGPU-IO: host-side GSP emulation for unmodified NVIDIA guest drivers
</subtitle>
<id>https://git.vgpu.io/open-iov.git/atom?h=lottery-m156-gate-attempt</id>
<link rel='self' href='https://git.vgpu.io/open-iov.git/atom?h=lottery-m156-gate-attempt'/>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/'/>
<updated>2026-10-15T21:50:57+00:00</updated>
<entry>
<title>vgsp-sema: m156 fail-closed release gate - withhold unwitnessed GR completion</title>
<updated>2026-10-15T21:50:57+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-15T21:50:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=eee9223116692285dece42568defbecb2e4e0cdf'/>
<id>urn:sha1:eee9223116692285dece42568defbecb2e4e0cdf</id>
<content type='text'>
Companion to the backend witness gate. A data-bearing forwarded GR
launch's completion release is now authored only when an executor was
witnessed (backend success = retirement wait observed writes, or the CUDA
bridge owns it, or an engine fault was delivered as the loud edge). When
the hold resolves with no witness, the release is withheld and the
channel's error notifier + event are delivered so the client observes a
launch failure instead of stale/zero output (r150 big-copy, r155 streams2
STREAMS bad=32768).

- svc_gr_rel_witnessed() gate at the two hold-resolution sites
  (svc_fwd_hold_expire_check, svc_fwd_hold_poll failure branch);
- svc_gr_failclosed_deliver() reuses the fault-deliver notifier tail
  (record shape + notifier_err latch) with the host-detected marker;
- a queued data-bearing GR launch now takes the hold even when the pass
  recorded no release of its own, so the deferred completion release always
  has an author (its success edge) and a withholder (its failure edge);
- the GR hold bound is raised to 40 s under the gate so the cold-context
  recovery chain (5 s + re-arm + 5 s + 3x2 s retries) can publish its
  outcome before the watchdog fires;
- new gr_failclosed counter in the work_guard summary line.

gsp_phys_rmcall_gr_failclosed=0 restores the historical behavior with one
switch. Build: make -j8 (kernel), green.
</content>
</entry>
<entry>
<title>vgsp-sema: m154 drop injected pins that collide with a live channel ring</title>
<updated>2026-10-15T16:08:53+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-15T16:08:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=e07c62b1fab2f2dbc9981458c0697829b287b01e'/>
<id>urn:sha1:e07c62b1fab2f2dbc9981458c0697829b287b01e</id>
<content type='text'>
r153 root cause (3rd-client userspace spin for the rest of the boot): the
guest scanner's merged CE-window run (va=0x121000000 len=0x40000; the
merged length varies per session) covered a CE channel's GPFIFO ring VA
0x121010000. svc_ipin_store took precedence in the ring read path, so the
ring read the guest page at the wrong PA (0x102e02000): an all-zero entry
was silently consumed, the pool release was never authored
(pushes frozen at 1643, crel frozen), and victory_matmul spun in
userspace for 50+ min. The ring VA translation must come from the
channel's own discovery path; an injected pin inside any live channel's
ring range is always wrong - drop it (counted + logged, first 8 per
session). Validated on the next cycle: 'injected pin ... DROPPED' lines
plus 'entry[1] raw!=0', advancing pushes, MATMUL bad=0 STATUS OK.
</content>
</entry>
<entry>
<title>vgsp-sema: budget the data window - only real device operands get the full span</title>
<updated>2026-10-14T18:25:24+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-14T18:25:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=4a23c19636692b8a25d840a76a37122aee5ce07a'/>
<id>urn:sha1:4a23c19636692b8a25d840a76a37122aee5ce07a</id>
<content type='text'>
r141 showed the 68-pages-per-pointer change starved the operands: the
launch's own QMD VA (0x204608000) and other low-VA candidates each consumed
68 window pages, so a 256 KB operand resolved 0 pages before the 205-page
cap. Give the full span only to high, cudaMalloc-shaped VAs, skip the QMD
VA entirely, and give every other candidate one page. Three 256 KB operands
(3x68=204) now fit.
</content>
</entry>
<entry>
<title>vgsp-gr: enlarge the data bounce window to 208 pages (256 KB operands)</title>
<updated>2026-10-14T18:05:41+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-14T18:05:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=fce5ab8d025799d71fbd260c4ef91a715497b54b'/>
<id>urn:sha1:fce5ab8d025799d71fbd260c4ef91a715497b54b</id>
<content type='text'>
victory_matmul (256x256 float: 256 KB per operand) failed with all-wrong
results while 128 KB workloads passed: the relocation bounce window was
112 pages with a 100-page data cap and 33 pages per pointer, so each 64-page
operand was truncated and the engine ran on partial/mismatched windows.

Grow the planted bounce window to 208 pages (main-PT slots 0x110..0x1df),
move the mail page to the last data-free slot (206, marker 207), and raise
the per-pointer cap to 68 pages and the data cap to 205 (three 256 KB
operands = 3x68 = 204 &lt;= 205). Operands larger than 256 KB still hit the cap
and need a chunked data path (documented at the define).
</content>
</entry>
<entry>
<title>vgsp-sema: author the PMA scrubber channel's progress (third-client scrub freeze)</title>
<updated>2026-10-14T15:39:30+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-14T15:39:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=624438bb0901680f416b879727b30a411dd3d78b'/>
<id>urn:sha1:624438bb0901680f416b879727b30a411dd3d78b</id>
<content type='text'>
The guest PMA scrubber (in-guest CeUtils CE channel, 4096 GPFIFO entries)
waits on its channel buffer's finish payload (offset 0x6c004) after the
third CUDA session's pages must be scrubbed; nothing in the emulation
authored it, so cudaMalloc froze in scrubCheckAndWaitForSize.

- channel_add: detect the 4096-entry scrubber channel and stash its USERD
  PA/ring geometry (the channel itself is left untouched: no rank change,
  no pump change - the colliding numeric-handle FREE may still unregister
  it, the geometry survives).
- sema_scrubbuf_add debug param: register the finish/host-semaphore word
  PAs the guest scanner resolves (vmallocinfo + kcore walk), because the
  RM kernel VA space collides numerically with the client CE window in the
  global VA map and cannot be resolved through it.
- svc_scrub_pass (service thread, per pass): from the channel's own USERD
  GPPut, track submitted scrub blocks across wraps, then author USERD
  GP_GET = put, host semaphore = put and finish payload = submitted.
  Forward-only, idempotent, zero writes while the scrubber idles.

Live-validated mechanism (r137 VM): authoring the finish word at the kcore-
resolved PA let the frozen victory_matmul leave scrubCheckAndWaitForSize
and proceed to its launch.
</content>
</entry>
<entry>
<title>vgsp-sema: reject all-FF continuation chunks in the CE push read; try the displaced pin pair</title>
<updated>2026-10-12T20:22:16+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-12T20:22:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=54a8f7b3385cccedac3f74a73ae9bc04089203d0'/>
<id>urn:sha1:54a8f7b3385cccedac3f74a73ae9bc04089203d0</id>
<content type='text'>
The r129 cross-page evidence: a 216-byte CE push whose SET_SEMAPHORE_A +
LAUNCH_DMA tail fell in the next 4 KB page, whose injected pin resolved to
an all-0xFF page while the first page decoded perfectly. A continuation
chunk read from an unvalidated source (injected pin, its displaced pair, or
the linear window guess) is now rejected when the whole chunk is 0xFF, the
displaced ipin-alt pair is tried as a new source, and a bounded line names
the rejected (va, pa, src) at the fix site.
</content>
</entry>
<entry>
<title>vgsp-sema: bounded sema-norel diagnostic for readable CE pushes without a release</title>
<updated>2026-10-12T19:48:29+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-12T19:48:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=f3cd10e0bdf5f4379c57f048d7e589612f8ac6e1'/>
<id>urn:sha1:f3cd10e0bdf5f4379c57f048d7e589612f8ac6e1</id>
<content type='text'>
The entries the pump holds for the 8 s CE grace are exactly the ones whose
decode found no release. Under SEMA_DBG this logs the decode state
(have_sem, rel va/payload, ops) and the first 64 push bytes for every
content-bearing CE push that decoded no release (2048-line budget,
all-zero reads are filtered so they cannot wash it out). Used in r129 to
show that a push whose tail crosses the CE page boundary reads 0xFF
garbage for its second page - the sem+LAUNCH_DMA live exactly in that
tail, so only boundary-crossing pushes were undecodable.
</content>
</entry>
<entry>
<title>vgsp-sema: persist the GR data-arg hold window across pump passes</title>
<updated>2026-10-12T17:25:31+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-12T17:25:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=b1075d754f6547b57fc4bdc3e1fc542001cbb981'/>
<id>urn:sha1:b1075d754f6547b57fc4bdc3e1fc542001cbb981</id>
<content type='text'>
The pump works on a snapshot copy of the channel table; without the
end-of-pass write-back the hold window was re-armed every pass and a
launch whose argument pointers never translate was never consumed (r122:
smiley's launch held forever). Persist gr_hold_until/gr_hold_idx so the
hold is exactly one bounded window per entry, then the entry is consumed
as before.
</content>
</entry>
<entry>
<title>vgsp-sema: hold GR launches whose device argument pointers do not translate; derive the CE vmap pairing per allocation</title>
<updated>2026-10-12T17:18:37+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-12T17:18:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=de595dc64d8e3a01a95282bacc5bc987510d7c5e'/>
<id>urn:sha1:de595dc64d8e3a01a95282bacc5bc987510d7c5e</id>
<content type='text'>
Two second-client zeros/stall countermeasures:

- svc_gr_data_fill now reports when a launch carries high (device-space)
  argument pointers and none of them resolves through any trusted source.
  svc_gr_request refuses to forward such a launch and leaves the capture
  unconsumed; the pump holds the ring entry for one bounded window per
  entry (gsp_sema_gr_grace_ms) and retries it, so a translation that
  appears a pass later (scanner pin, published directory, learned pair)
  is used instead of executing the kernel against unresolved pointers.
  On window expiry the entry is consumed exactly as before (bounded
  zeros, never a hang). Bounded per-session fill diagnostics name the
  source that serves each candidate (ipin/pin/lat/map/vas/disc/win) and
  dump the published vaspace walk results for misses.

- The CE push-buffer kcore chain resolver derives its vmap page offset
  per allocation instead of using a fixed shift: the rm_mem size is read
  from its real offset (570.144 layout) and paired with the vmallocinfo
  area page count, so a leading header page is only skipped when it
  actually exists. With an unreadable size the two candidate offsets are
  content-probed with the host's method-stream plausibility test and an
  ambiguous result keeps the status-quo pairing. This removes the
  off-by-one that fed wrong push pages to the pump (content-rescue
  crawl).
</content>
</entry>
<entry>
<title>vgsp-sema: pair CE push-buffer vmap pages with the right offset; validated rescues repair injections</title>
<updated>2026-10-12T16:13:10+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-12T16:13:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=1612492982479bc4e1f722c8e52d22ef37b0280f'/>
<id>urn:sha1:1612492982479bc4e1f722c8e52d22ef37b0280f</id>
<content type='text'>
The CE push-buffer uvm_rm_mem is vmalloc'd as a 4097-page area: one
leading page plus the 4096-page (16 MB) GPU data window, so GPU data
page k lives at vmap page k+1. The kcore chain resolver paired page k
with vmap page k, pinning the adjacent push for every page; the pump
then read the wrong push, decode failed, and the host fell into the
content rescue which crawled one entry per ~2 s (r115: rescue_run=4202,
entry_va=0x12001b18c repeating). Verified against five independent
content-validated rescue anchors (k=20..28, all delta +1), and the vmap
area boundary confirms the extra page (nv_vm_map_pages 4097 pages).

Five fixes:
 - resolve_mem_pins() takes page_off; the CE chain and uvbp push-buffer
   paths pass mem_page_off() (1 when the vmap is exactly 16 MB + 1 page;
   0 for direct-mapped mems like the semaphore pool).
 - a content-validated rescue page now also replaces the injected-pin
   entry (svc_rescue_try / svc_rescue_run_try), so a stale or wrong
   injection can no longer shadow the validated page and re-run the
   rescue on every pass.

Evidence: r115 rescue anchors va 0x120014000-&gt;pa 0x12a2e2000 .. va
0x12001c000-&gt;pa 0x12a2de000 all at vmap offset k+1; the candidate pages
decode as the adjacent push (wrong semaphore payload) before the fix.
</content>
</entry>
</feed>
