summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 09:11:55 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 09:11:55 -0400
commit51e50d937800db01bd95010ad54ef2c4ea140b75 (patch)
tree354f39a3c024ab6eadfaf12c33b6ff0259db5762
parent6c845235b806b942d6760e7432bc3e318b65609c (diff)
downloadopen-iov-51e50d937800db01bd95010ad54ef2c4ea140b75.tar.gz
open-iov-51e50d937800db01bd95010ad54ef2c4ea140b75.zip
vgsp-sema: prefer the client's page tables over a disagreeing pool pin (moved-but-readable pool)
The pool resolver trusted an injected pin after a read-back proof. That proof does not catch a pool page that MOVED: the old page is still readable, so the release write lands on the old page while the client polls the new one. Observed: 'pending release starved va=0x12100000x tries=64' for ~45 s with the stale pin (pa=0x120b30000) readable, until the fresh pin (pa=0x130e9d000) arrived; the client's tracker never woke and its init hung (multikernel battery timeout, copies stuck rc=-2). The client's own page tables are the GPU/UVM ground truth for where the tracker reads, so when a structural walk resolves a different page than the pin (and it is not a degenerate identity), the walk wins - both sources are read-back proven at the exact offset.
-rw-r--r--kernel/gsp_sema_service.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 2634220..dcce4b5 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3622,11 +3622,50 @@ static int svc_pool_pa_resolve(struct nv_vgpu_device *vgpu, u32 h, u64 va,
* the injected page is readable before trusting it; a failed
* proof falls through to the read-back-validated cache, the
* structural walk and the targeted rm_mem record.
+ *
+ * r536: the read-back proof does NOT catch a moved pool whose
+ * OLD page is still readable - the write then lands on the old
+ * page while the client polls the new one and the tracker
+ * starves (observed: "pending release starved va=0x12100000x
+ * tries=64" for ~45 s after the pool moved, with the stale pin
+ * pa=0x120b30000 still readable; the fresh pin pa=0x130e9d000
+ * arrived 45 s later). The client's OWN page tables are the
+ * GPU/UVM ground truth for where the tracker reads, so when a
+ * structural walk resolves a DIFFERENT page than the pin, the
+ * walk wins (both are read-back proven at the exact offset).
*/
u32 probe = 0;
if (!svc_read_ap(vgpu, pa, svc_ap_of(a), &probe,
sizeof(probe))) {
+ u64 wpa = 0;
+ int wap = SVC_APERTURE_SYS;
+ bool walk_hit = false;
+
+ if (!svc_walk_discovered(vgpu, page, &wpa, &wap) ||
+ !svc_walk_vaspaces(vgpu, page, &wpa, &wap))
+ walk_hit = true;
+ if (walk_hit &&
+ (wpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ (pa & ~(u64)(SEMA_PAGE_SIZE - 1)) &&
+ !svc_pool_pa_identity(va, wpa)) {
+ u32 wprobe = 0;
+ u64 exact = (wpa & ~(u64)(SEMA_PAGE_SIZE - 1)) |
+ (va & (SEMA_PAGE_SIZE - 1));
+
+ if (!svc_read_ap(vgpu, exact, svc_ap_of(wap),
+ &wprobe, sizeof(wprobe))) {
+ svc_pool_pa_store(va, exact, wap);
+ svc_tr_clear_failure(page);
+ if (src)
+ *src = "walk-over-pin";
+ svc_pool_pa_note(h, va, exact,
+ "walk-over-pin");
+ *addr = exact;
+ *ap = wap;
+ return 0;
+ }
+ }
svc_tr_clear_failure(page);
if (src)
*src = "pin";