summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-20 01:56:24 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-20 01:56:24 -0400
commitc72f89483dec5507024efc26d945bf0674c66db7 (patch)
treeb3810912ae4cc173e3bf5cf3e82e817d8be19c8e
parentae7848021ec10dd25c48f3244c4bca7adc79f2d5 (diff)
downloadopen-iov-c72f89483dec5507024efc26d945bf0674c66db7.tar.gz
open-iov-c72f89483dec5507024efc26d945bf0674c66db7.zip
vgsp: read the status-queue consumption cursor from the command queue (SWAP_RX)
Under MSGQ_FLAGS_SWAP_RX (both sides set it; flags=1 in both headers) the guest driver's msgqRxMarkConsumed writes its STATUS readPtr to pOurRxHdr->readPtr, and the driver's pOurRxHdr is the COMMAND-queue buffer's RX header (msgq.c msgqRxLink swap branch: pReadOutgoing = &pOurRxHdr->readPtr with pOurRxHdr from msgqTxCreate's pBackingStore = pCommandQueue). The status queue's own +rxHdrOff is the mirror we publish - our command-queue read position. The status free-space check read the mirror, so it tracked our own writes: with the guest mid-drain the ring was declared full (free=0, peer=0, write=62/63), replies were written into it anyway, unread records were overwritten, and the guest RM read a newer record - GspMsgQueueReceiveStatus: Bad sequence number. Expected 447 got 510. Possible memory corruption. - after which every RPC failed (status 0x25) and the first client's cudaMalloc returned device busy or unavailable. That is the boot lottery: on a lost boot the first client (mail) FAILs and the boot is poisoned for every later client. Evidence (r330 vs r332): r330 mail FAILed at the first cudaMalloc and only one channel unregistered in the whole boot (the guest RM never tore its channels down after the status desync); with the fix r332 mail + matmul pass and every client's channels unregister (79 unregisters, one session flush per client). Also adds bounded diagnostics: sema-d2hmap (per-page destination resolution of >=1MB host-dest copies) and a raised DIVERGE witness budget.
-rw-r--r--kernel/gsp_rm_emulation.c42
-rw-r--r--kernel/gsp_sema_service.c20
2 files changed, 46 insertions, 16 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 764ef05..cd9cbf2 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -571,27 +571,39 @@ static int gsp_rm_send_flags(struct gsp_emu_context *ctx, u32 function,
u32 used, space, rxoff = 0;
u8 shdr[32];
- if (gsp_rm_read_buf(ctx, rm->stat_off, shdr,
- sizeof(shdr)))
+ /*
+ * r332 SWAP_RX cursor fix: the guest's consumption
+ * cursor for the STATUS queue lives in the COMMAND
+ * queue's RX header, not in the status queue's own
+ * rxHdrOff. Under MSGQ_FLAGS_SWAP_RX (both sides set
+ * it: flags=1 in both headers) the driver's
+ * msgqRxMarkConsumed writes its status readPtr to
+ * pOurRxHdr->readPtr, and the driver's pOurRxHdr is
+ * the COMMAND-queue buffer's RX header (msgq.c
+ * msgqRxLink swap branch: pReadOutgoing =
+ * &pOurRxHdr->readPtr with pOurRxHdr from
+ * msgqTxCreate's pBackingStore = pCommandQueue). The
+ * status queue's own +rxHdrOff is the mirror we
+ * publish: OUR command-queue read position
+ * (written below after every consumed command
+ * record). Reading that mirror here made the
+ * free-space math track our own writes: the ring was
+ * declared "full" with the guest mid-drain, replies
+ * were written into it anyway, unread records were
+ * overwritten, and the guest RM read a newer record
+ * ("Bad sequence number. Expected N got N+63") - the
+ * first-client cudaMalloc then fails with "device
+ * busy or unavailable" (the boot lottery) and every
+ * later RPC fails until a fresh boot.
+ */
+ if (gsp_rm_read_buf(ctx, rm->cmd_off, shdr, sizeof(shdr)))
break;
memcpy(&rxoff, shdr + 24, 4);
if (!rxoff || rxoff >= 0x1000)
break;
- if (gsp_rm_read_buf(ctx, rm->stat_off + rxoff,
- &peer_read, 4) ||
+ if (gsp_rm_read_buf(ctx, rm->cmd_off + rxoff, &peer_read, 4) ||
peer_read >= rm->stat_msgcount)
break; /* no usable cursor: blind write */
- /*
- * fail4: only a cursor the guest is actually BEHIND
- * (peer <= our writePtr) is a consumption cursor.
- * The observed value at stat+rxHdrOff under this
- * queue's flags tracks writePtr+1 (a mirror), and
- * gating on it silenced every wake-up event and
- * wedged the clients. A mirror (peer > write) falls
- * back to the historical blind write.
- */
- if (peer_read > rm->stat_write)
- break;
have_peer = true;
used = (rm->stat_write + rm->stat_msgcount -
peer_read) % rm->stat_msgcount;
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4c063db..fb096f1 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3962,6 +3962,7 @@ static void svc_session_flush(void); /* defined next to the pending queue */
#define SVC_LEDGER_EVICT_RESET 256u
static u32 svc_ledger_n;
static u64 svc_ledger_diverges;
+static u32 svc_d2hmap_log; /* D2H-MAP per-page destination budget */
static u64 svc_ledger_stores;
static u64 svc_ledger_evictions;
static u64 svc_ledger_evict_since_reset;
@@ -5880,6 +5881,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
u32 aper = 0;
u64 lpa = 0;
u32 lap = 0;
+ u32 wprov = 0;
if (svc_op_translate(vgpu, dst_orig + o, &pa, &aper)) {
/*
@@ -5892,6 +5894,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
pa = lpa;
aper = (lap == SVC_APERTURE_FB) ?
CE_APERTURE_VID : CE_APERTURE_SYS;
+ wprov = 0xF1;
} else if (dst_orig >= SVC_VAS_FLOOR &&
!svc_ledger_lookup(dst_orig + o, &lpa, &lap) &&
((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) !=
@@ -5906,12 +5909,27 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
* stay consistent with it.
*/
svc_ledger_diverges++;
- if (svc_ledger_diverges <= 32)
+ if (svc_ledger_diverges <= 512)
pr_info("sema-ledger: DIVERGE write va=0x%llx prev=0x%llx cur=0x%llx\n",
dst_orig + o, lpa, pa);
pa = lpa;
aper = (lap == SVC_APERTURE_FB) ?
CE_APERTURE_VID : CE_APERTURE_SYS;
+ wprov = 0xF0;
+ } else {
+ wprov = svc.op_tr_src;
+ }
+ /*
+ * D2H-MAP (diagnostic): per-page destination
+ * resolution of large host-dest copies - the direct
+ * witness for which guest pages a readback lands on.
+ * Bounded; one line per 4 KB page of copies >= 1 MB.
+ */
+ if (total >= (1u << 20) && !(o & (SEMA_PAGE_SIZE - 1)) &&
+ svc_d2hmap_log < 4096u) {
+ svc_d2hmap_log++;
+ pr_info("sema-d2hmap: va=0x%llx o=%zu pa=0x%llx ap=%u prov=%u\n",
+ dst_orig + o, o, pa, aper, wprov);
}
if (aper == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;