summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-20 16:52:11 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-20 16:52:11 -0400
commitebc6386cd769f6017e6f48296eeb5e5ae0d52c80 (patch)
treee133e14f8eea90c44928b62c9f15b53082cce536 /kernel/gsp_sema_service.c
parenta1455655b68f5fd9710f764be8e6afbed5b2a81c (diff)
downloadopen-iov-ebc6386cd769f6017e6f48296eeb5e5ae0d52c80.tar.gz
open-iov-ebc6386cd769f6017e6f48296eeb5e5ae0d52c80.zip
sema: pin-wins wave - a fresh pin re-homes the landing table (svc_handle_map_add) and wins over the ledger in svc_gr_page_note, svc_gr_data_fill and svc_fill; gate the displaced-pin fan-out on a current pin match
Root cause class (sub-agent audit + r371 log forensics): the landing table (ledger) moved only on host writes, so a VA re-pinned to a NEW page (CUDA reuses VA ranges across processes) kept resolving to the OLD, freed page. Every later write through that entry landed on memory the guest kernel had since reused - the r371 mail client's guest oops (NULL page array in nv_free_system_pages, 8 zero bytes) is this class. Fixes: (1) svc_handle_ map_add repairs a disagreeing ledger entry from the fresh pin (PIN-REPAIR); (2) svc_gr_page_note and svc_gr_data_fill keep a live pin over the ledger (PIN-WINS); (3) svc_fill checks the pin before the ledger fallback; (4) the pool alt fan-out writes the displaced page only while the current pin still names it (alt_skip). New diag: pinrep= alt_skip=.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c165
1 files changed, 158 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 6f73f0f..f9ab990 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3118,6 +3118,11 @@ static void svc_pool_wr_note(u32 h, u64 va, u64 pa, const char *src,
}
}
+/* r372: landing-table entries repaired from a fresh pin (stale-ledger class). */
+static u64 svc_ledger_pin_repairs;
+/* r372: pool alt fan-outs skipped because the primary pin moved on. */
+static u64 svc_pool_alt_skipped;
+
/*
* Fan a pool release out to the last displaced translation of the same page
* (see svc_ipin_alt): the primary target may be the stale one when two host
@@ -3141,6 +3146,27 @@ static void svc_pool_alt_apply(struct nv_vgpu_device *vgpu, u32 h, u64 va,
return;
if ((pa & ~(u64)(SEMA_PAGE_SIZE - 1)) == page)
return; /* never write an identity translation */
+ /*
+ * r372 (stale-ledger corruption class): fan out ONLY while the
+ * current primary pin for this VA still names the displaced page.
+ * Once a newer pin has displaced it, the old page belongs to a
+ * buffer the guest has freed - writing it lands on whatever the
+ * guest kernel reused the page for. A missing current pin is
+ * equally unprovable: skip. The primary release write already
+ * succeeded either way, so this is a lost best-effort, not a
+ * failure.
+ */
+ {
+ u64 cpa = 0;
+ int cap = SVC_APERTURE_SYS;
+
+ if (svc_ipin_lookup(va, &cpa, &cap) ||
+ ((cpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ (pa & ~(u64)(SEMA_PAGE_SIZE - 1)))) {
+ svc_pool_alt_skipped++;
+ return;
+ }
+ }
if (svc_read_ap(vgpu, pa, svc_ap_of(ap), &cur, sizeof(cur)))
return;
if (cur >= val)
@@ -4200,11 +4226,12 @@ static void svc_rebuild(struct nv_vgpu_device *vgpu)
* content" window. n approaching SVC_LEDGER_MAX or evict > 0 in a
* client's window is the tell.
*/
- pr_info("sema-svc: ledger n=%u/%u stores=%llu evict=%llu resets=%llu diverges=%llu pinwins=%llu reloc_div=%llu rewrites=%llu\n",
+ pr_info("sema-svc: ledger n=%u/%u stores=%llu evict=%llu resets=%llu diverges=%llu pinwins=%llu reloc_div=%llu rewrites=%llu pinrep=%llu alt_skip=%llu\n",
svc_ledger_n, SVC_LEDGER_MAX, svc_ledger_stores,
svc_ledger_evictions, svc_ledger_evict_resets,
svc_ledger_diverges, svc_ledger_pinwins,
- svc_ledger_reloc_diverges, svc_ledger_rewrites);
+ svc_ledger_reloc_diverges, svc_ledger_rewrites,
+ svc_ledger_pin_repairs, svc_pool_alt_skipped);
/*
* P6b wave 1: guest-forwarding summary. Printed whenever any counter
* moved (not only on requests) so a run that captured no candidate is
@@ -4587,15 +4614,43 @@ static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem,
if (!phys) {
/* Virtual destination: the VA shadow first (its pages stay
- * authoritative), then the unified landing table (the page a
- * previous write of this VA landed on - always the
- * authoritative location of the content), then the pinned
- * map and the VA->PA map. */
+ * authoritative), then a live pin (the guest's newest
+ * statement - r372: a re-pinned VA must not be written
+ * through a stale landing), then the unified landing table
+ * (the page a previous write of this VA landed on - always
+ * the authoritative location of the content), then the
+ * pinned map and the VA->PA map. */
u64 pa;
u32 aper;
if (svc_vas_has(addr)) {
shadow = true;
+ } else if (!svc_pin_lookup_any(addr, &pa, &aper)) {
+ u64 lpa = 0;
+ u32 lap = 0;
+
+ /*
+ * r372 pin-wins: repair the landing table when it
+ * still names the pre-re-pin page, so every later
+ * reader follows the pin too.
+ */
+ if (!svc_ledger_lookup(addr, &lpa, &lap) &&
+ (((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ (pa & ~(u64)(SEMA_PAGE_SIZE - 1))) ||
+ (u32)lap != (u32)aper)) {
+ svc_ledger_pin_repairs++;
+ if (svc_ledger_pin_repairs <= 32)
+ pr_info("sema-ledger: PIN-WINS fill-dst va=0x%llx ledger=0x%llx/%u pin=0x%llx/%u\n",
+ addr,
+ lpa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ lap, pa, aper);
+ svc_ledger_store(addr,
+ pa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ aper);
+ }
+ addr = pa;
+ aperture = (aper == SVC_APERTURE_FB) ?
+ CE_APERTURE_VID : CE_APERTURE_SYS;
} else if (!svc_ledger_lookup(addr, &pa, &aper)) {
addr = pa;
aperture = (aper == SVC_APERTURE_FB) ?
@@ -16353,6 +16408,43 @@ static void svc_gr_page_note(struct nv_vgpu_device *vgpu, u64 va, u32 qmd_word)
u64 lpa = 0;
u32 lap = 0;
+ /*
+ * r372 pin-wins: a live injected pin is the guest's newest
+ * statement about this VA. If it disagrees with the landing
+ * table, the pin wins and the table is repaired (see the
+ * PIN-REPAIR note in svc_handle_map_add): the old landing was
+ * a freed page, and resolving the launch there wrote engine
+ * output onto memory the guest kernel had reused.
+ */
+ {
+ u64 ipa = 0;
+ int iap = SVC_APERTURE_SYS;
+
+ if (!svc_ipin_lookup(page, &ipa, &iap)) {
+ u64 lpa2 = 0;
+ u32 lap2 = 0;
+
+ if (svc_ledger_lookup(page, &lpa2, &lap2) ||
+ ((lpa2 & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ (ipa & ~(u64)(SEMA_PAGE_SIZE - 1))) ||
+ (u32)lap2 != (u32)iap) {
+ svc_ledger_pin_repairs++;
+ if (svc_ledger_pin_repairs <= 32)
+ pr_info("sema-ledger: PIN-WINS note va=0x%llx ledger=0x%llx/%u pin=0x%llx/%d\n",
+ page, lpa2, lap2, ipa, iap);
+ svc_ledger_store(page,
+ ipa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ (u32)iap);
+ }
+ svc_fwd_req.gr_pages[i].pa =
+ ipa & ~(u64)(SEMA_PAGE_SIZE - 1);
+ svc_fwd_req.gr_pages[i].ap = (u8)iap;
+ svc_pin_store(page,
+ ipa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ iap);
+ return;
+ }
+ }
if (!svc_ledger_lookup(page, &lpa, &lap)) {
u64 rpa = 0;
u32 rap = 0;
@@ -17229,8 +17321,34 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
if (va >= SVC_VAS_FLOOR) {
u64 lpa = 0;
u32 lap = 0;
+ u64 ipa = 0;
+ int iap = SVC_APERTURE_SYS;
- if (!svc_ledger_lookup(va, &lpa, &lap) &&
+ /*
+ * r372 pin-wins: when a live pin exists it is the
+ * newest truth; the landing table may name a page
+ * the guest has since freed (VA reuse across
+ * clients). Keep the pin and repair the table.
+ * Only a pin-less VA still follows the table.
+ */
+ if (!svc_ipin_lookup(va, &ipa, &iap)) {
+ pa = ipa;
+ ap = (u32)iap;
+ if (!svc_ledger_lookup(va, &lpa, &lap) &&
+ (((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ (ipa & ~(u64)(SEMA_PAGE_SIZE - 1))) ||
+ (u32)lap != (u32)iap)) {
+ svc_ledger_pin_repairs++;
+ if (svc_ledger_pin_repairs <= 32)
+ pr_info("sema-ledger: PIN-WINS fill va=0x%llx ledger=0x%llx/%u pin=0x%llx/%d\n",
+ va,
+ lpa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ lap, ipa, iap);
+ svc_ledger_store(va,
+ ipa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ (u32)iap);
+ }
+ } else if (!svc_ledger_lookup(va, &lpa, &lap) &&
((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
(pa & ~(u64)(SEMA_PAGE_SIZE - 1)) ||
(u32)lap != (u32)ap)) {
@@ -21055,6 +21173,39 @@ static void svc_handle_map_add(void)
}
svc_ipin_store(va, req.pa + off, ap);
svc_lat_store(va, req.pa + off, ap);
+ /*
+ * r372 (stale-ledger corruption class): a fresh pin is the
+ * guest's newest statement of where this VA's content
+ * lives. The landing table (ledger) otherwise only moves
+ * on host writes, so a VA re-pinned to a NEW page (the
+ * guest freed the old buffer and reallocated it - CUDA
+ * reuses VA ranges across processes) kept resolving to
+ * the OLD, freed page: every later write through that
+ * ledger entry landed on memory the guest kernel had
+ * since reused (proven class: 8 zero bytes into an
+ * nv_free_system_pages page array -> guest oops at
+ * client teardown). Repair the entry only when it
+ * disagrees with the pin (a no-op otherwise, so the
+ * table is not flooded with pin pages).
+ */
+ {
+ u64 lpa = 0;
+ u32 lap = 0;
+
+ if (!svc_ledger_lookup(va, &lpa, &lap) &&
+ (((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
+ ((req.pa + off) & ~(u64)(SEMA_PAGE_SIZE - 1))) ||
+ (u32)lap != (u32)ap)) {
+ svc_ledger_pin_repairs++;
+ if (svc_ledger_pin_repairs <= 32)
+ pr_info("sema-ledger: PIN-REPAIR va=0x%llx old=0x%llx ap=%u -> new=0x%llx ap=%u\n",
+ va,
+ lpa & ~(u64)(SEMA_PAGE_SIZE - 1),
+ lap,
+ req.pa + off, ap);
+ svc_ledger_store(va, req.pa + off, ap);
+ }
+ }
}
/*
* m149: bounded per-session evidence that the CE push-buffer