Support vendor VFIO vGPU devices - #321
Conversation
199b1d1 to
a93d009
Compare
d893fce to
de4742a
Compare
de4742a to
18e047f
Compare
|
Trimmed over-engineering after an architectural review against the parent task (host kernel 6.8 / Ubuntu 24.04 support). Most of the removed weight came from earlier review-round additions rather than the original design: |
7ef1f8d to
bf21162
Compare
bf21162 to
83c53ea
Compare
…ion test by framework A vGPU assignment goes stale when its release succeeds but the metadata save does not (or start fails between the release and its first save). The in-process owner map only covers assignments created since the last restart and the VFIO handle scan only covers VMs that have opened the device, so after a restart a stale release could still write 0 to a VF during another live instance's pre-open boot window. Consult live instance metadata on every release: when another instance with a live hypervisor process claims the same device path, drop the stale metadata without touching the device. The integration test asserted mdev specifics (UUID, /sys/bus/mdev path) and failed before exercising the lifecycle on a vendor VFIO host. Branch the assertions by framework and extend the test to cover release on stop and reacquisition on start. Also report an absent-but-possibly-valid profile as ambiguous instead of 'not found': the vendor VFIO creatable catalog is capacity-dependent, so a valid larger profile disappears while smaller ones remain.
83c53ea to
79eef07
Compare
kill(pid, 0) returning EPERM means the process exists but cannot be signaled. Both the reconcile protection set and the stale-claim check treated that as dead, which could release a VF under a live VM. Reuse processExists (EPERM-aware, zombie-filtering) in the claim check and handle EPERM in the reconcile scan.
| target, err := os.Readlink(filepath.Join(s.pciDevicesPath, vfAddress, "iommu_group")) | ||
| if os.IsNotExist(err) { | ||
| return false, nil | ||
| } |
There was a problem hiding this comment.
VFIO probe skips sibling check
High Severity
The vfioDeviceInUse function prematurely returns false if either the vfio-dev or iommu_group sysfs path is missing. This short-circuits the check, incorrectly marking a VF as unused even when a running QEMU VM holds an active device handle. This can lead to current_vgpu_type being cleared for an active VM during destroy or reconcile.
Reviewed by Cursor Bugbot for commit ff9462f. Configure here.
ab2b0e8 to
19b9602
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 19b9602. Configure here.
A bare kill(0) check treats any process that reused a stored hypervisor PID as the owning VMM, so a reused PID could keep an orphaned VF in the startup protected set or make a stale record look like a live claim during release. Require the PID to own the instance's hypervisor socket on Linux in both paths. Also retain assignment metadata when start's vGPU rollback fails, matching create and stop, so later release paths can still find the device path instead of leaking the slot until the next restart.


background
The current migration target is NVIDIA vGPU Manager R19 (R580) on Ubuntu 24.04 / kernel 6.8. For SR-IOV vGPUs, that host uses NVIDIA's vendor-specific VFIO framework: each VF is assigned a profile directly through its
nvidia/sysfs attributes and the VF itself is passed to the VM (no mdev UUIDs). Existing GPU hosts continue to use mdev, so both frameworks must coexist while hosts migrate one at a time: hypeman detects the host's framework at runtime and leaves the mdev path intact.Note that
/sys/class/mdev_bus/itself may still be present on a vendor VFIO host, becausenvidia_vgpu_vfiopulls in themdevmodule. It just never gains parent entries, so detection keys off discovered mdev VFs rather than the directory existing.summary
creatable_vgpu_typescurrent_vgpu_typewith least-loaded-GPU placement/dev/vfio/devices/*) and the legacy/dev/vfio/<group>nodeStacked on #322, which contains the framework-neutral lifecycle refactor.
creatable_vgpu_typesformatThe driver emits a table with a header row and the type ID first:
Parsing splits on the
:separator and skips the header row. An earlier revision expected the name first and the type ID last, which failed on every line (parse vGPU type ID "Name"), and becausegetVGPUStatusdiscards profile errors the host advertised vGPU mode with all its slots and no profiles at all — no placement could succeed.Once a profile consumes a GPU's entire framebuffer, the remaining VFs on that GPU print the header and nothing else. That is a legitimately empty list rather than a malformed file, so it yields zero profiles instead of an error; otherwise one 48Q allocation would remove the whole GPU from the status response.
host validation
Validated on an L40S host running vGPU Manager 580.159.01 on Ubuntu 24.04 / kernel 6.8.0-136, where the driver reports
Host VGPU Mode: SR-IOVand/sys/class/mdev_bus/has no parents:NVIDIA L40S-48Qon one GPU, and returns to 64 after release. Assigning a smaller profile instead clamps that GPU's remaining VFs to the same framebuffer size class (2B/2Q/2Aafter a2Q), matching how the mdev driver reportsavailable_instancesAvailability counts free VFs that can currently accept a profile, not how many of that profile fit — the driver enforces the framebuffer limit at assignment time. That is the pre-existing mdev behavior and this PR keeps it; tightening the count is separate work.
current_vgpu_typeand booting QEMU with-device vfio-pci,sysfsdev=<VF>produces a liveNVIDIA L40S-1Qinnvidia-smi vgpu, released by writing0/dev/vfio/<group>node, not an iommufd cdev, even with/dev/iommupresent — so the legacy group fd check is the one that keeps assignments alive on this hostNVIDIA L40S-2Q; guest GRID loaded, CDP and kernel-images-api started, hardware OpenGL reported the L40S through ANGLE, and NVENC completed an encodecurrent_vgpu_typetests
go test -race ./lib/devices ./lib/instances -run 'VendorVFIO|CreatableVGPU|StoredVGPU|StandbyRejectsVendorVFIO' -count=1go test ./lib/devices ./lib/hypervisor/qemu ./lib/resources -count=1go test ./cmd/api ./cmd/api/api ./lib/instances ./integration -run '^$' -count=1go vet ./cmd/api ./lib/devices ./lib/hypervisor/qemu ./lib/instances ./lib/resourcesreview follow-ups
DiscoverVGPU);ListGPUProfilesWithVFstakes the framework instead of re-detecting, removing the repeated full VF scans per GPU status queryDestroyVGPUinfers the framework for metadata written beforeGPUFrameworkexistedscope decisions
The implementation stays scoped to the validated R19 / Ubuntu 24.04 target:
creatable_vgpu_typesformat; the parser accepts only theID : Nametable the target driver emitscurrent_vgpu_typeand QEMU opening the VFIO device; open-handle probing cannot cover that interval. After a restart, fail-closed VFIO handle probing protects recovered assignmentsDestroyVGPU/resourcesreports an empty profile list (slot counts still show exhaustion); a last-known-catalog cache was considered and rejected — it would be stale across restarts and no caller makes placement decisions from that list — metadata with a device path always carriesGPUFramework; only mdev-UUID-only legacy metadata needs inferenceVGPUAssignmentstruct instead of positional string parameterslistProfilesreads each VF'screatable_vgpu_typesonce per listing instead of twice (catalog + availability in one pass)Note
High Risk
Changes GPU assignment, sysfs writes, and startup reconciliation on security-sensitive multi-tenant infrastructure; incorrect cleanup could disturb live VMs, though protection and fail-closed VFIO probes mitigate that.
Overview
Adds NVIDIA vendor VFIO as a second SR-IOV vGPU path next to mdev: hosts are classified at runtime via
DiscoverVGPU()(mdev VFs first, else VFs withnvidia/creatable_vgpu_types). Vendor VFIO assigns profiles by writingcurrent_vgpu_type, picks VFs with least-loaded-GPU placement, and releases by writing0, with per-instance ownership until QEMU opens VFIO and reconciliation that scans open iommufd and legacy/dev/vfio/<group>handles.API startup now runs
ReconcileVGPUswith device paths protected for instances whose hypervisor PID still owns the instance socket (ListInstancesForReconcile+HypervisorProcessExists). If the instance list fails, vendor VFIO reconcile is skipped rather than running unprotected.Instance lifecycle passes
InstanceIDinto vGPU destroy, clears stale assignments when another live instance claims the same path, retains metadata when create-time vGPU teardown fails, and extends integration tests for sysfs assignment, stop/release, and start/reacquire on both frameworks. GPU resource reporting uses discovery instead of removedDetectHostGPUMode, with warnings on discovery/profile errors.Reviewed by Cursor Bugbot for commit d92201d. Bugbot is set up for automated code reviews on this repo. Configure here.