Detect wedged vGPU VFs from the guest and report to the health store - #435
Detect wedged vGPU VFs from the guest and report to the health store#435yummybomb wants to merge 8 commits into
Conversation
d312338 to
7d54fb9
Compare
7d54fb9 to
9a90223
Compare
9a90223 to
0ff16d1
Compare
0ff16d1 to
3db5546
Compare
3db5546 to
b35501a
Compare
b3bf925 to
55a0d6f
Compare
55a0d6f to
ee1b160
Compare
a5dc229 to
fed19c4
Compare
7bd4f52 to
67b2b24
Compare
67b2b24 to
0662ad9
Compare
f3bf0cc to
ff54c20
Compare
ff54c20 to
37bc190
Compare
yummybomb
left a comment
There was a problem hiding this comment.
reviewed the change against hypeship/vendor-vfio-vgpu and traced the sentinel through guest output, host log scanning, durable health state, placement, and admission. the persistence rollback and assignment-identity handling are coherent, but the serial marker is not actually source-authenticated, and timed-out probes can overlap in the exact uninterruptible-ioctl case this code targets.
leaving the first finding as a blocker; github does not allow this account to request changes on its own PR.
|
|
||
| // Require a standalone guest-agent line so echoed marker text cannot count against a VF. | ||
| var ( | ||
| vgpuSentinelFailedPattern = regexp.MustCompile(`^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[guest-agent\] (HYPEMAN-GPU-INIT-FAILED ts=\S+ nvrm="NVRM: [^"\r\n]*RmInitAdapter failed![^"\r\n]*")\r?\n?$`) |
There was a problem hiding this comment.
blocker: a standalone line does not establish that the guest agent wrote it. In exec mode the customer entrypoint's stdout/stderr is wired directly to the same serial console (lib/system/init/mode_exec.go:132-133), so an ordinary workload can print a complete line matching this regex without root or /dev/kmsg access. Repeating that across assignments can quarantine healthy VFs, and the runbook's statement that only a root guest can forge this is therefore incorrect. Please carry the report over a channel whose source the host can distinguish (for example a dedicated guest-agent RPC/transport), or otherwise authenticate the source; matching the log shape is not sufficient here.
| case err := <-done: | ||
| return err | ||
| case <-timer.C: | ||
| _ = cmd.Process.Kill() |
There was a problem hiding this comment.
this bounds how long the caller waits, but not the attempt's lifetime. If nvidia-smi is stuck in the uninterruptible ioctl described above, Kill does not make cmd.Wait return; the process and waiter goroutine remain live while probeGPUInitUntil launches another attempt after 15s. The 10-minute loop can therefore accumulate many concurrent stuck probes on the VF. Can we retain the in-flight attempt and avoid launching another until it is reaped (or stop retrying once an attempt cannot be killed), so there is at most one outstanding nvidia-smi?
88f3c3d to
b901282
Compare
b901282 to
1fd824a
Compare
a805d59 to
aa66cd3
Compare
1084aef to
b23a654
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b23a654. Configure here.
b49bc73 to
a53ca5c
Compare
The guest agent watches /dev/kmsg for kernel-facility NVRM RmInitAdapter-failed records and emits a standalone HYPEMAN-GPU-INIT-FAILED marker (repeated so printk splits cannot lose it), and probes driver init at boot with nvidia-smi -L when present, emitting a terminal HYPEMAN-GPU-INIT-OK on success. A hung probe attempt is bounded to 30 seconds. A host sentinel controller tails each vendor VFIO instance's app.log, matches only complete standalone markers, revalidates the assignment before reporting, and feeds failures and successes into the VF health store. Start archives the previous boot's app log before persisting a new assignment so stale markers cannot count against the new VF, and create allocates the vGPU immediately before metadata persistence to minimize the unpersisted window. vGPU reconciliation preserves assignments when hypervisor liveness is uncertain and records the condition in logs and a metric. GPU.md gains the detection and sentinel documentation.
… scan Markers share the serial console with workload stdout, so a bare log line does not establish that the guest agent wrote it: a workload could print an exact FAILED line to quarantine its healthy VF, or an OK line to clear a real failure record. The guest agent now serves its observed GPU init state over the existing vsock gRPC channel (GetGPUInitStatus), and the sentinel only acts on a marker the guest agent corroborates. Markers from instances whose agent is unreachable (e.g. already stopped) are skipped and logged; a wedged VF still convicts through its next assignment. Also fixes in the same scan path: - A clear whose persist fails is remembered on the tail and retried on later scans (and once more before a reassignment replaces the tail), since the once-per-boot OK marker is already consumed by then. - Only the latest marker in a pass is dispatched, so a FAILED with a later OK - a resolved pair replayed after a hypeman restart - is not recorded again. - When copy-truncate rotation moves unread bytes to the .1 backup, the scanner reads the backup remainder before restarting at offset zero, instead of dropping unseen markers. - The guest probe reaps a timed-out nvidia-smi before returning, so a probe stuck in an uninterruptible ioctl cannot accumulate processes.
…rkers The sentinel now polls GetGPUInitStatus over vsock for every vendor VFIO instance on its 5s tick and acts on the guest agent's reported state directly. The serial-console markers, the log scanner, and its offset, rotation, replay, and pending-clear bookkeeping are removed; the health store's per-assignment dedup makes polling idempotent and a failed persist retries on the next tick. The response carries the NVRM failure line so quarantine logs keep their diagnostic detail.
A stopped or standby instance whose vGPU release failed retains its assignment metadata, so the sentinel polled it forever: a permanent rpc_error every tick, and QEMU vsock dials by guest CID alone, so a reused CID could reach an unrelated live guest. Gate targets on the control socket, the same no-VMM signal deriveState uses. Also hold polling until vendor-VFIO discovery is confirmed instead of scanning while discovery errors are still being retried.
a53ca5c to
86fb40e
Compare

Summary
Top half of the wedged-VF work, stacked on #462 (the VF health store, placement exclusion, admission, and
/resourcesfields). This PR adds the detection path that feeds that store./dev/kmsgfor kernel-facilityNVRM: ... RmInitAdapter failed!records and exposes the current GPU initialization state overGetGPUInitStatusvia vsock.Safety and failure handling
nvidia-smiattempt is killed after 30 seconds. The guest agent waits for that process to be reaped before retrying, so an attempt stuck in uninterruptible I/O cannot accumulate concurrent probes; the independent kmsg watcher still reports the underlying init failure.Observability
hypeman_instances_vgpu_sentinel_init_failures_totalhypeman_instances_vgpu_sentinel_quarantines_totalhypeman_instances_vgpu_sentinel_checks_totalbyresult(ok,failed,unknown,rpc_error,unsupported_agent, orlist_error)hypeman_instances_vgpu_quarantined_vfshypeman_instances_vgpu_vf_health_store_unavailablehypeman_instances_vgpu_reconcile_liveness_uncertain_totallib/devices/GPU.mdgains the detection and sentinel documentation.Out of scope
An operator force-cycle endpoint. Recovery remains the documented manual DCGM quiesce, SR-IOV cycle, state edit, restart, and verification flow.
Testing
Passed:
The full
lib/instancesrace suite did not complete cleanly locally because its integration tests require additional host networking and image tooling and surfaced unrelated dependency races.The underlying wedge signal and manual recovery sequence were previously validated on L40S hardware. A live end-to-end run of the guest watcher and host controller is still required before merge, including two failed assignments and the success path.
Note
Medium Risk
Changes vGPU placement safety, automatic VF quarantine, and create/reconcile timing on GPU hosts; incorrect guest signals or assignment confirmation could remove capacity, though running instances are not detached.
Overview
Adds an automatic detection path for wedged vendor-VFIO virtual functions: the guest agent watches
/dev/kmsgfor kernelNVRMRmInitAdapter failed!lines (and optionally probes withnvidia-smi -L), exposesGetGPUInitStatusover vsock, and the newVGPUSentinelControllerpolls running vendor-VFIO instances every 5s (up to 64 concurrent) to record failures and successes into the VF health store from #462.Host wiring: Wire injects
VGPUSentinelControllerandmainstarts it alongside other background controllers. Create path now allocates the vGPU immediately before metadata persistence so assignments are less likely to exist only in memory.VF health store: Adds
RepairVFHealthStore(used once per sentinel tick); failure/success reports no longer auto-retry a failed persist on every call—they fail closed until repair succeeds. vGPU reconcile treats ambiguous hypervisor liveness as “preserve assignment” with a warning andhypeman_instances_vgpu_reconcile_liveness_uncertain_total.Docs/metrics:
GPU.mddocuments sentinel behavior, metrics (sentinel_checks_total, quarantine gauges, store-unavailable), and tightened error text for failed-create retention stubs.Reviewed by Cursor Bugbot for commit b23a654. Bugbot is set up for automated code reviews on this repo. Configure here.