diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 20:49:08 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 20:49:08 -0400 |
| commit | e25b9b9e37bb0612bc17d2e8c1710e1c4950cd80 (patch) | |
| tree | 2059fbfb98e1cfcabbef339abc9a87daf8afbbd8 /kernel | |
| parent | 1e5be920add0dfd2d5c388b9cf8a4a09f3e72e37 (diff) | |
| download | open-iov-e25b9b9e37bb0612bc17d2e8c1710e1c4950cd80.tar.gz open-iov-e25b9b9e37bb0612bc17d2e8c1710e1c4950cd80.zip | |
vgsp r580: walk-over-bootcache for pool pages + event burst dedup and fast-path hint
Pool resolution (thread: the starve wedge surviving the r577 fix): the
boot-scoped pool cache survives session flushes, but a pool page MOVES
between sessions and the old page often stays readable, so the read-back
proof cannot tell - the resolver wrote releases to the stale cache PA while
the client's tracker read its current page. Live evidence (r579 boot):
pool-wr src=bootcache pa=0x11e6d9000 for va=0x121000000 while the injected
pin/current page was pa=0x134730000; the client spun in uvm_tracker_wait
for minutes. svc_pool_pa_resolve now tries the structural walk (the
client's own page tables) BEFORE trusting the cache: a differing,
read-proven walk page wins (src=walk-over-boot) and the cached page is kept
as the fan-out secondary.
Event burst (r579 boot: events_dropped=724, the 'no postable event
(events_n=8 dropped=724)' sentinel every 0.5 s): apply the 250 ms per-event
dedup to the per-completion shotgun (8 records per completion burned the
48/s budget), and hoist the completion hint above the pump fast path so it
runs under load too (a dropped wake is re-posted within 0.5 s).
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 14 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 93 |
2 files changed, 88 insertions, 19 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index fb0f31d..2a957b3 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -882,6 +882,20 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src) for (i = 0; i < rm->events_n; i++) { if (!rm->events[i].valid) continue; + /* + * r580: apply the hint dedup to the per-completion + * shotgun. Every completion posts ALL registered + * events (the ABI gives no source association), so a + * completion burst burns the burst budget 8 records + * per completion and real wake-ups get dropped + * (r579 boot: events_dropped=724). A redundant + * re-post within 250 ms adds no wake-up - the + * client's dispatcher re-reads channel state on any + * event - and the 0.5 s hint re-posts late waiters. + */ + if (time_before(jiffies, rm->events[i].last_post + + GSPRM_EVENT_HINT_DEDUP)) + continue; gsp_rm_fill_ev_payload(rm, i, payload); { int rc = gsp_rm_send_flags(ctx, diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 444298a..4fd160e 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -3895,6 +3895,51 @@ static int svc_pool_pa_resolve(struct nv_vgpu_device *vgpu, u32 h, u64 va, if (!svc_pool_boot_lookup(va, &pa, &a)) { u32 bprobe = 0; + /* + * r580: the boot cache survives session flushes, but a pool + * page MOVES between sessions (the client's new allocation) + * while the old page often stays readable - the read-back + * proof cannot tell. The client's own page tables are the + * ground truth for where ITS tracker reads, so try the + * structural walk BEFORE trusting the cache: a differing, + * read-proven walk page wins and the cached page stays as the + * fan-out's secondary candidate. Live evidence (r579 boot): + * releases were written to the stale cache pa=0x11e6d9000 + * while the current page was 0x134730000 (the pin) and the + * client's tracker starved; the pool-wr line said + * src=bootcache. + */ + { + u64 wpa2 = 0; + int wap2 = SVC_APERTURE_SYS; + bool walk_hit = false; + + if (!svc_walk_discovered(vgpu, page, &wpa2, &wap2) || + !svc_walk_vaspaces(vgpu, page, &wpa2, &wap2)) + walk_hit = true; + if (walk_hit && + (wpa2 & ~(u64)(SEMA_PAGE_SIZE - 1)) != + (pa & ~(u64)(SEMA_PAGE_SIZE - 1)) && + !svc_pool_pa_identity(va, wpa2)) { + u64 exact = (wpa2 & ~(u64)(SEMA_PAGE_SIZE - 1)) | + (va & (SEMA_PAGE_SIZE - 1)); + + if (!svc_read_ap(vgpu, exact, svc_ap_of(wap2), + &bprobe, sizeof(bprobe))) { + svc_pool_boot_store(va, pa, a); + svc_pool_pa_store(va, exact, wap2); + svc_tr_clear_failure(page); + if (src) + *src = "walk-over-boot"; + svc_pool_pa_note(h, va, exact, + "walk-over-boot"); + *addr = exact; + *ap = wap2; + return 0; + } + } + } + if (!svc_read_ap(vgpu, pa, svc_ap_of(a), &bprobe, sizeof(bprobe))) { svc_tr_clear_failure(page); @@ -25633,6 +25678,32 @@ static int svc_thread(void *arg) * progress. (With two guests, any guest's progress keeps the * loop tight; the next iteration pumps both.) */ + /* + * r580: the completion hint must also run while the pump is + * making progress - the fast path below skips it, and a + * completion burst saturates the event burst budget and drops + * wake-ups (r579 boot: events_dropped=724; the sentinel + * "no postable event (events_n=8 dropped=724)" repeated every + * 0.5 s). A client that starts waiting mid-burst needs the + * 0.5 s re-post even under load; the per-event dedup keeps the + * extra volume bounded. + */ + for (g = 0; g < n_vgpus; g++) { + vgpu = vgpus[g]; + if (time_before(jiffies, + (unsigned long)svc.post_hint_until) && + time_after(jiffies, + (unsigned long)svc.last_hint + HZ / 2)) { + int rc; + + svc.last_hint = jiffies; + rc = gsp_rm_post_all_events(vgpu); + if (gsp_sema_dbg) + pr_info_ratelimited("sema-svc: completion hint rc=%d\n", + rc); + } + } + if (pumped) { msleep(1); continue; @@ -25644,30 +25715,14 @@ static int svc_thread(void *arg) /* * Push-buffer base discovery: a chunked walk of guest * RAM finds the pages whose first push names a - * channel, so a channel that appears with work - * already waiting is pinned and pumped without - * waiting for the rolling sweep. */ svc_pb_discover(vgpu); /* - * Completion hint: re-post the events for a few - * seconds after a completion, so a client that starts - * waiting after the edge-triggered wake-up still - * observes it. + * r580: the completion hint was hoisted above the + * pumped fast path (it must run under load too); it is + * not repeated here. */ - if (time_before(jiffies, - (unsigned long)svc.post_hint_until) && - time_after(jiffies, - (unsigned long)svc.last_hint + HZ / 2)) { - int rc; - - svc.last_hint = jiffies; - rc = gsp_rm_post_all_events(vgpu); - if (gsp_sema_dbg) - pr_info_ratelimited("sema-svc: completion hint rc=%d\n", - rc); - } /* * Fast path for the pushes themselves: every mapped |
