Skip to content

vmm: sanitize GPUs through vfio-ioctls hot reset - #1065

Open
kvinwang wants to merge 4 commits into
nextfrom
fix/gpu-sbr-vfio-ioctls
Open

vmm: sanitize GPUs through vfio-ioctls hot reset#1065
kvinwang wants to merge 4 commits into
nextfrom
fix/gpu-sbr-vfio-ioctls

Conversation

@kvinwang

@kvinwang kvinwang commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • switch GPU sanitize-on-attach from root-only sysfs writes to VFIO_DEVICE_PCI_HOT_RESET
  • use rust-vmm/vfio abstractions instead of maintaining handwritten VFIO ioctl numbers, ABI structs, and variable-length buffer parsing in dstack
  • validate the kernel-reported reset scope and reject affected devices outside the GPU's IOMMU group
  • keep devices bound to vfio-pci across the reset
  • add dstack-vmm sanitize-gpu <slot>... for standalone validation and operations

Dependency strategy

rust-vmm/vfio already provides the VFIO bindings and container/group/device lifecycle abstractions, but its public API does not yet expose PCI hot reset operations. This PR temporarily pins the following fork commit:

The fork adds pci_hot_reset_info and pci_hot_reset APIs. After validating the complete flow on GPU hardware, we plan to submit those APIs upstream and replace the Git dependency with a released crates.io version.

Motivation

The existing sanitize path writes Bridge Control through sysfs and re-probes devices through /sys/bus/pci/drivers_probe. Both operations require root privileges. The VMM normally runs as a dedicated unprivileged user that already has access to the VFIO group nodes required for GPU passthrough.

The VFIO hot-reset ioctl asks the kernel to perform the bus reset and authorizes it through ownership of every affected VFIO group. This is the same mechanism used by VMM implementations such as QEMU.

Safety

  • retain the dedicated-bridge topology check
  • query the kernel-reported affected-device set before resetting
  • reject any affected device outside the target GPU's IOMMU group
  • pass the owned VFIO group to the reset ioctl as proof of ownership
  • drop all VFIO objects before QEMU starts

Tests

  • cargo check -p dstack-vmm
  • cargo test -p dstack-vmm — 119 passed
  • cargo clippy -p dstack-vmm --all-targets -- -D warnings

The new reset path has not yet been validated on target GPU hardware. The standalone sanitize-gpu command is included to exercise the exact launch-time path during that validation.

Relationship to #1058

This is an alternative implementation of #1058 that addresses the review feedback to use vfio-ioctls. PR #1058 has not been modified.

Leechael and others added 3 commits August 17, 2026 06:03
The sanitize-on-attach path issued the Secondary Bus Reset by writing
Bridge Control in the upstream bridge sysfs config space and re-probed
devices through /sys/bus/pci/drivers_probe. Both files are writable by
root only, so the feature could not be enabled in production where
dstack-vmm runs as an unprivileged user with no sudo.

Switch to the VFIO_DEVICE_PCI_HOT_RESET ioctl, which makes the kernel
perform the same bus reset. The ioctl is authorized by device ownership
rather than privilege: the caller presents fds for every VFIO group
affected by the reset, and the /dev/vfio group nodes are the same ones
QEMU opens to attach the GPU, so the VMM user already has access.

A single group fd suffices because every sanitized GPU sits alone
behind a dedicated PCIe bridge and alone in its IOMMU group. The bridge
topology check is kept as defense, and the kernel-reported set of
affected devices must all belong to the GPU own group or the launch is
aborted. Devices stay bound to vfio-pci across the reset, so the
drivers_probe re-probe logic is no longer needed and is removed.

Not yet validated on GPU hardware; see
plans/2026-08-14-vfio-gpu-hot-reset.md for the pending experiment.
Expose the sanitize path as "dstack-vmm sanitize-gpu <slot>..." so
operators can reset GPUs by hand and the pending hardware experiment
can exercise exactly the code path used at VM launch, running as the
unprivileged VMM user. The subcommand needs no server configuration,
only /dev/vfio access, and is handled before config loading like the
other special modes.
Copilot AI lite review requested due to automatic review settings August 17, 2026 13:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@kvinwang
kvinwang force-pushed the fix/gpu-sbr-vfio-ioctls branch from ff467dc to 3d9c161 Compare August 17, 2026 13:46
@Leechael

Leechael commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Validated this on real Blackwell hardware — an 8× B200 host with Intel TDX, all GPUs bound to vfio-pci, one GPU per IOMMU group, CC mode on. Built from this branch and exercised through the new sanitize-gpu subcommand.

The hot-reset path works. Single GPU and all eight, with the GPUs idle:

sanitize-gpu <one slot>    -> all sanitized GPUs are VFIO-ready count=1 elapsed_ms=2024
sanitize-gpu <eight slots> -> all sanitized GPUs are VFIO-ready count=8 elapsed_ms=2099

Reset scope per GPU is reported as the GPU alone, consistent with the one-GPU-per-group topology. CC mode survives the reset, and the devices come back bound to vfio-pci with their cdev nodes intact.

Two observations from the run:

1. sanitize-gpu opens the legacy group node, while the VMM hands QEMU the iommufd cdev. The reset path goes through /dev/vfio/<group>, but VMs are started with -object iommufd plus /dev/vfio/devices/vfioN. Those are mutually exclusive in the kernel, so while a device is still attached to an iommufd context the group open returns EBUSY. The gpu_reset.rs module doc says the group nodes "are the same ones QEMU opens", which stopped being true once configure_gpus moved to -object iommufd.

This matters in practice on a confidential-VM host, where the device stays attached for a while after the guest has powered down and QEMU has exited — lsof shows no holder, yet both the group open and VFIO_DEVICE_BIND_IOMMUFD fail until the VM's memory teardown completes. So sanitize-gpu is usable only once the VMM reports the VM fully stopped, not merely when the guest is down. Worth a line in the subcommand's help or docs.

2. Non-fatal error during the 8-GPU run. One GPU logged, from vfio-ioctls cleanup:

ERROR vfio_ioctls::vfio_ioctls::vfio_syscall: VFIO_GROUP_UNSET_CONTAINER ioctl failed: Invalid argument (os error 22)
ERROR vfio_ioctls::vfio_device: Could not unbind VFIO group: <n>

The reset itself succeeded and the remaining seven proceeded normally, so it looks like a teardown-path issue rather than a functional one, but it was reproducible.

Separately: switching away from the root-only sysfs bridge-control write is a real operational improvement. On the previous path the VMM, running as an unprivileged user, needed group-writable config on both each GPU and its upstream bridge, which does not survive a reboot without extra machinery. Removing that requirement is worth the change on its own.

(Testing note, not a defect of this PR: we ran this branch against 0.6.0-rc0 images, which it is not targeted at — Image::version_tuple parses each dot-separated component as u16, so a semver pre-release suffix fails to parse and make_sys_config then reports Unsupported image version: (0, 0, 0). We patched that locally to get the branch onto our images. Only relevant to whoever backports this.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants