diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-22 10:06:05 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-22 10:06:05 -0400 |
| commit | 83e3761ed85d802675eee4c20c27e57aabf251da (patch) | |
| tree | 5de8acdecfe47222eb63c6222b46a29127498421 /kernel | |
| parent | 7df79840ceae3b0b05720c489afe35d471fa7e49 (diff) | |
| download | open-iov-83e3761ed85d802675eee4c20c27e57aabf251da.tar.gz open-iov-83e3761ed85d802675eee4c20c27e57aabf251da.zip | |
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.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 54 |
1 files changed, 54 insertions, 0 deletions
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; |
