From 83e3761ed85d802675eee4c20c27e57aabf251da Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 22 Oct 2026 10:06:05 -0400 Subject: r459 THE mid-boot degradation root cause: the 8-slot VA-space table filled with dead clients' registrations and every new client after the 8th got no slot Evidence (r466 boot, one battery): 23 distinct 'VA space 0x... page directory ... entries=4' registrations and ZERO 'VA space ... dropped' lines. The guest driver does not always tear a client's VA space down (client exit, crash, or a switch the RM emulation does not forward), so after eight registrations svc.vas[] had no free slot: gsp_sema_service_vaspace_add silently refused the new directory (the 'if (vs)' guard), svc_walk_vaspaces kept walking only the dead clients' directories, and every walk of the new client's VAs failed -> its CE copies returned rc=-2 forever ('sema-optrace ... rc=-2' x8151 in the r466 log; the 10th+ client of the boot: streams2 bad=32737, streams_events no output, smiley hung, and the same class on r463/r465). This is the 'no launch stalls / no mid-boot degradation' blocker. Fix: - svc_vaspace_add evicts the least-recently-registered entry when the table is full instead of refusing (logged), and stamps every registration; - svc_walk_vaspaces orders the snapshot by registration stamp, newest first, so a live client's directory is the authority and a stale one (whose guest memory the driver has since reused) can only answer when the live directory cannot. --- kernel/gsp_sema_service.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'kernel/gsp_sema_service.c') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index abc9b06..756e644 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -486,6 +486,12 @@ struct svc_vaspace { u64 pdb; u32 entries; /* root entry count */ int ap; /* SVC_APERTURE_* of the directory itself */ + unsigned long stamp; /* r459: last registration/use; LRU evict + * when the table is full (a stale entry from + * a dead client otherwise blocks every new + * client after the 8th registration: the + * mid-boot walk failure that made the 10th+ + * client's copies fail rc=-2) */ }; struct svc_lat { @@ -1600,12 +1606,40 @@ void gsp_sema_service_vaspace_add(const struct sema_vaspace_desc *desc) if (!vs && !svc.vas[i].valid) vs = &svc.vas[i]; } + /* + * r459: the table is 8 slots and the guest driver does not always + * send a teardown for a client's VA space (observed: 23 distinct + * registrations, 0 drops in one boot). Once all slots hold a dead + * client's directory, a NEW client's registration found no slot and + * every walk of its VAs failed (copies rc=-2, launches reading + * stale pages - the 10th-client mid-boot degradation). Evict the + * least-recently-registered entry instead of refusing the new one; + * the old client is gone and its directory pointer is dead guest + * memory, so the eviction can only remove stale authority. + */ + if (!vs) { + unsigned long oldest = 0; + int oi = 0; + + for (i = 0; i < SVC_MAX_VASPACES; i++) { + if (!svc.vas[i].valid) + continue; + if (!oldest || time_before(svc.vas[i].stamp, oldest)) { + oldest = svc.vas[i].stamp; + oi = i; + } + } + vs = &svc.vas[oi]; + pr_info("sema-svc: VA space table full; evicting 0x%x (pdb=0x%llx) for 0x%x\n", + vs->h_vaspace, vs->pdb, desc->h_vaspace); + } if (vs) { vs->valid = true; vs->h_vaspace = desc->h_vaspace; vs->pdb = desc->pdb; vs->entries = desc->num_entries; vs->ap = desc->b_vidmem ? SVC_APERTURE_FB : SVC_APERTURE_SYS; + vs->stamp = jiffies; /* A new directory invalidates what we learned from the old one. */ memset(svc.lat, 0, sizeof(svc.lat)); } @@ -1933,6 +1967,26 @@ static int svc_walk_vaspaces(struct nv_vgpu_device *vgpu, u64 va, } spin_unlock_irqrestore(&svc.vas_lock, flags); + /* + * r459: try the NEWEST registration first. A dead client's stale + * directory (the table outlives clients; only 8 slots) can still + * resolve a VA - through guest memory the driver has since reused - + * to a wrong page, and the first success wins. Ordering by the + * registration stamp makes the live client's directory the + * authority and only falls through to older ones when it cannot + * answer. + */ + for (i = 1; i < n; i++) { + struct svc_vaspace k = local[i]; + int j = i - 1; + + while (j >= 0 && time_before(local[j].stamp, k.stamp)) { + local[j + 1] = local[j]; + j--; + } + local[j + 1] = k; + } + for (i = 0; i < n; i++) { int alt; -- cgit v1.2.3