diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-08 11:07:42 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-08 11:07:42 -0400 |
| commit | d3e67a9e9f9db2f5f4b5d5d04635b61ac6c566aa (patch) | |
| tree | b58b52df758bea0694a2e7cc05aa46bcf7b6b7c3 /kernel | |
| parent | 54bc80ae33addabc73a5bc1b0881423a63bc9862 (diff) | |
| download | open-iov-d3e67a9e9f9db2f5f4b5d5d04635b61ac6c566aa.tar.gz open-iov-d3e67a9e9f9db2f5f4b5d5d04635b61ac6c566aa.zip | |
vgsp-sema: kernel-native pool release translation + starvation telemetry (ISSUE-0001)
svc_pool_pa_resolve() could translate an UVM pool/waiter page only from
watcher pins, the read-back cache, the self-discovered directory and a
targeted rm_mem scan. When the userspace watcher races a boot and the
self-discovered directory has no entry yet, a starved completion release
sits in svc_pending[] forever (p13-r4: applied frozen at 89/90, gr_rel=0),
the guest tracker never wakes and CUDA blocks at DEVICE. Add:
- svc_walk_vaspaces() (the driver-published page directories - the walker
svc_lookup_trusted always used, previously absent here);
- a final proof-gated svc_lookup_trusted() fallback (also the only path
that triggers svc_pd_discover()).
Both read-back proven like every other source. Plus per-entry starvation
telemetry (tries + bounded logs) so a future stall names the exact va.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 100 |
1 files changed, 98 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 48c070b..30b349b 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -2288,6 +2288,46 @@ static int svc_pool_pa_resolve(struct nv_vgpu_device *vgpu, u32 h, u64 va, return 0; } } + /* + * Kernel-native driver-published ground truth: walk the VAS page + * directories the guest's driver publishes to us via + * svc_walk_vaspaces - the same walker svc_lookup_trusted has always + * used for ring/VA translations, but deliberately absent from this + * pool resolver until now. + * + * The pool resolver could previously translate only from + * watcher-injected pins, the read-back cache, the self-discovered + * directory and a targeted rm_mem scan. On boots where the userspace + * watcher races (its kprobes arm after the client's first CE push, + * the scanner misses the injection window, ...) and the + * self-discovered directory has not learned the pool's page tables + * yet, every one of those sources can miss. The completion release + * for the client's last CE push then sits in svc_pending[] forever: + * svc_apply_pending() logs "not translatable yet: keep" every pass, + * the guest's uvm_tracker_wait_for_entry never wakes, the client + * never creates its GR channels, and the CUDA context setup spins at + * DEVICE with an empty GR ring. That is the stalled-boot signature + * (ISSUE-0001); walking the driver-published directories removes + * the watcher race from the completion path instead of retrying + * around it. Read-back proven like every other source, so a stale + * directory entry cannot poison a release. + */ + if (!svc_walk_vaspaces(vgpu, page, &wpa, &wap)) { + u64 exact = (wpa & ~(u64)(SEMA_PAGE_SIZE - 1)) | + (va & (SEMA_PAGE_SIZE - 1)); + + if (!svc_read_ap(vgpu, exact, svc_ap_of(wap), &probe, + sizeof(probe))) { + svc_pool_pa_store(va, exact, wap); + svc_tr_clear_failure(page); + if (src) + *src = "vaspaces"; + svc_pool_pa_note(h, va, exact, "vaspaces"); + *addr = exact; + *ap = wap; + return 0; + } + } if (!svc_targeted_resolve(vgpu, va, &pa)) { /* Read back before trusting: an unreadable page is not kept. */ if (!svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, &probe, @@ -2302,6 +2342,29 @@ static int svc_pool_pa_resolve(struct nv_vgpu_device *vgpu, u32 h, u64 va, return 0; } } + /* + * Last resort: the general resolver chain (watcher pins of any kind, + * the learned latency/map caches, the driver-published and + * self-discovered walks, then svc_pd_discover(), whose one-shot + * page-directory discovery is NOT reachable from any source above - + * svc_pd_discover() only ever runs from inside svc_lookup_trusted()). + * Without this call the pool resolver could miss forever on a boot + * where the self-discovered directory has not been populated yet + * even though the driver-published page tables are present in guest + * RAM. Proof-gated like every other source. + */ + if (!svc_lookup_trusted(vgpu, va, &pa, ap)) { + if (!svc_read_ap(vgpu, pa, svc_ap_of(*ap), &probe, + sizeof(probe))) { + svc_pool_pa_store(va, pa, *ap); + svc_tr_clear_failure(page); + if (src) + *src = "trusted"; + svc_pool_pa_note(h, va, pa, "trusted"); + *addr = pa; + return 0; + } + } return -ENOENT; } @@ -5976,6 +6039,16 @@ struct svc_pending_release { u64 va; u32 payload; u32 op; /* 0 = RELEASE, 1 = REDUCTION (add payload) */ + /* + * Resolution attempts that found no translation for this VA. + * Telemetry for ISSUE-0001: a pending release that keeps failing to + * translate starves the guest's tracker wait forever (the client + * never reaches GR setup). Historically that state was invisible in + * the logs - svc_apply_pending() just retried quietly. The counter + * makes the starvation nameable (VA + payload + age) whenever it + * happens again. + */ + u32 tries; }; static struct svc_pending_release svc_pending[SVC_PENDING_MAX]; @@ -6000,6 +6073,21 @@ static void svc_pending_add(u64 va, u32 payload, u32 op) svc_pending[i].va = va; svc_pending[i].payload = payload; svc_pending[i].op = op; + svc_pending[i].tries = 0; +} + +/* + * Loud, bounded telemetry for a starved deferred release (ISSUE-0001). + * Called from the two "no translation yet, keep" paths of + * svc_apply_pending() with an incremented try count; logs at 4/64/1024 + * attempts so a live stall names the exact VA that is starving the guest + * tracker without flooding a healthy run. + */ +static void svc_pending_note_starved(struct svc_pending_release *p) +{ + if (p->tries == 4 || p->tries == 64 || p->tries == 1024) + pr_info("sema-svc: pending release starved va=0x%llx payload=%u tries=%u (no VA->PA for the pool/waiter page; the guest tracker cannot complete until this applies)\n", + p->va, p->payload, p->tries); } static void svc_apply_pending(struct nv_vgpu_device *vgpu) @@ -6022,16 +6110,24 @@ static void svc_apply_pending(struct nv_vgpu_device *vgpu) */ if (svc_pool_pa_resolve(vgpu, 0, p->va, &ppa, &pap, NULL)) { - i++; /* not translatable yet: keep */ + /* not translatable yet: keep (ISSUE-0001) */ + p->tries++; + svc_pending_note_starved(p); + i++; continue; } if (svc_read_ap(vgpu, ppa, svc_ap_of(pap), &cur, sizeof(cur))) { + p->tries++; + svc_pending_note_starved(p); i++; continue; } } else if (svc_sem_read(vgpu, p->va, &cur)) { - i++; /* translation still missing: keep waiting */ + /* translation still missing: keep waiting */ + p->tries++; + svc_pending_note_starved(p); + i++; continue; } if (p->payload <= cur) { |
