The Diagnostic Probe: Unraveling GPU Passthrough Bindings in a Proxmox Migration
Introduction
In the complex dance of migrating AI workloads between physical hosts, few moments are as critical as the one captured in message 6767 of this opencode session. The assistant has just finished installing the NVIDIA driver (version 580.126.09) on the kpro5 Proxmox host, expecting to see the two RTX A6000 GPUs ready for passthrough to an LXC container running Qwen3.6-27B. Instead, a discovery in the previous message (msg 6766) revealed that all five GPUs on the system—both the target A6000s and the three RTX 3090s reserved for other VMs—are stubbornly bound to the vfio-pci driver. Message 6767 is the assistant's systematic diagnostic probe to understand why this binding exists and how to selectively unbind only the A6000s. It is a masterclass in methodical debugging under uncertainty.
The Scene: A Migration in Progress
The broader context is a hardware migration. The user's kpro6 node was decommissioned, and its LXC container (CT129) was moved to kpro5—a machine with a heterogeneous GPU mix: two RTX A6000s (Ampere GA102, 48GB each) and three RTX 3090s. The 3090s are already assigned to running virtual machines, while the A6000s are intended for CT129 to serve the Qwen3.6-27B dense model, a 55GB BF16 model requiring approximately 96GB of GPU memory across two cards.
The assistant had just completed a multi-step NVIDIA driver installation: blacklisting the open-source nouveau driver, installing the exact proxmox-headers-6.8.12-9-pve kernel headers, downloading the 580.126.09 driver from NVIDIA's official repository, and running the .run installer with DKMS. The installation log showed successful kernel module compilation and loading. Yet when the assistant queried nvidia-smi, it found nothing—because the GPUs were not bound to the NVIDIA driver at all.
The Discovery That Triggered the Probe
Message 6766 was the moment of discovery. The assistant ran lspci -k and found that every NVIDIA GPU on the system was bound to vfio-pci, the Virtual Function I/O driver used for PCI passthrough to virtual machines. This is a standard configuration in Proxmox environments where GPUs are dedicated to VMs, but it becomes a problem when you want to share GPUs between host processes (like an LXC container running SGLang) and VMs. The assistant's immediate question: where is this binding configured, and can I unbind only the A6000s without affecting the 3090-bound VMs?
The Subject Message: A Systematic Diagnostic
Message 6767 is the assistant's response to that question—a single bash command executed over SSH on the kpro5 host, composed of four diagnostic probes chained together:
ssh root@10.1.2.5 'cat /proc/cmdline && echo "---" && ls /etc/modprobe.d/ && echo "---" && lsmod | grep vfio && echo "---" && for d in 4f:00.0 53:00.0 57:00.0 ce:00.0 d6:00.0; do echo -n "PCI $d driver: "; ls -l /sys/bus/pci/devices/0000:$d/driver 2>/dev/null | awk -F/ "{print \$NF}"; done'
Each segment targets a different potential source of the vfio-pci binding:
1. Kernel command line (/proc/cmdline): The assistant checks for boot-time parameters that might configure vfio, such as iommu=on, iommu=pt, or vfio-pci.ids=.... The kernel cmdline is a common place to specify which PCI devices should be bound to vfio-pci at boot. The output reveals a minimal Proxmox boot configuration: initrd=\EFI\proxmox\6.8.12-9-pve\initrd.img-6.8.12-9-pve root=ZFS=rpool/ROOT/pve-1 boot=zfs vmlinuz. No vfio-related parameters are present. This is a significant negative result—it rules out the most common mechanism for persistent vfio binding.
2. Modprobe configuration directory (ls /etc/modprobe.d/): The assistant checks for configuration files that might load the vfio-pci module with specific device IDs. The standard approach in Proxmox is to create a file like /etc/modprobe.d/vfio.conf containing options vfio-pci ids=10de:.... The directory listing shows only three files: blacklist-nouveau.conf (created earlier in this session to disable the open-source driver), pve-blacklist.conf (a Proxmox standard file), and zfs.conf. No vfio configuration file exists. This is another negative result—the binding is not configured through the conventional modprobe mechanism.
3. Loaded kernel modules (lsmod | grep vfio): The assistant confirms that despite the absence of explicit configuration, the vfio modules are loaded and active. The output shows vfio_pci, vfio_pci_core, vfio_iommu_type1, vfio, iommufd, and irqbypass—the full stack required for PCI passthrough. Notably, vfio_pci has a usage count of 4 (the Used by column), indicating four devices are bound to it, while the probe checks five PCI addresses. This discrepancy hints that one GPU might be bound differently, or that the count includes non-GPU vfio devices.
4. Per-PCI-device driver binding: The assistant iterates over all five NVIDIA GPU PCI addresses (4f:00.0, 53:00.0, 57:00.0, ce:00.0, d6:00.0) and queries each device's current driver symlink. Every single one reports vfio-pci. This confirms the binding is universal across all GPUs, not selective.
The Thinking Process Visible in the Probe
The assistant's reasoning is evident in the structure of the command. It is following a classic debugging pattern: eliminate the obvious explanations first, then examine the state more closely. The kernel cmdline is the most direct way to configure vfio-pci bindings—check it first. The modprobe.d directory is the second most common mechanism—check it next. The loaded modules confirm the mechanism is active. Finally, the per-device check confirms the scope of the problem.
The choice of PCI addresses is also telling. The assistant includes all five GPUs (4f:00.0 is an A6000, 53:00.0 and 57:00.0 are 3090s, ce:00.0 is the second A6000, d6:00.0 is the third 3090), plus the audio function of one GPU (4f:00.1 was checked in the previous message but omitted here for brevity). This shows the assistant has already mapped the GPU topology and knows exactly which devices belong to which physical card.
The Puzzle: Where Does the Binding Come From?
The results create an intriguing puzzle. The vfio-pci binding is active across all five GPUs, but neither the kernel cmdline nor the modprobe.d directory contains any vfio configuration. How is this possible?
There are several plausible explanations, each requiring different follow-up actions:
Proxmox dynamic binding: Proxmox can dynamically bind PCI devices to vfio-pci when a VM with PCI passthrough is started. If VMs using the 3090s were running (or had been started since boot), Proxmox would have bound those GPUs to vfio-pci. However, this wouldn't explain why the A6000s—which are not assigned to any VM—are also bound. The A6000s might have been bound during the previous configuration on kpro6 and the binding persisted across the migration.
Driver probe order: The NVIDIA driver and vfio-pci might be competing for the same devices. If vfio-pci claims the devices before the NVIDIA driver probes them, the NVIDIA driver never gets a chance. This is why the blacklist-nouveau.conf was created—to prevent the nouveau driver from claiming the GPUs first. A similar mechanism might be needed for vfio-pci.
Persistent state from kpro6: The CT129 container was migrated from kpro6, which had a different GPU configuration. If the vfio-pci binding was configured on kpro6 and the configuration was carried over (perhaps in the LXC config or in a shared storage pool), it might be applying bindings that no longer match the hardware topology.
Input Knowledge Required
To fully understand this message, one needs knowledge of several technical domains:
PCI passthrough and vfio: Understanding that vfio-pci is a driver that binds to PCI devices to make them available for passthrough to virtual machines. When a GPU is bound to vfio-pci, it is invisible to the host's NVIDIA driver and can only be used by a VM or LXC that has been configured for PCI passthrough.
Proxmox VE architecture: Proxmox uses a custom kernel based on Ubuntu's kernel with additional patches for virtualization. It supports both VM-level (KVM) and container-level (LXC) GPU passthrough. The pve-blacklist.conf file is a standard Proxmox file that blacklists drivers for devices managed by the hypervisor.
Linux kernel module configuration: The /etc/modprobe.d/ directory contains configuration files that control kernel module loading, including driver blacklisting and device binding rules. The /proc/cmdline file contains the kernel boot parameters passed by the bootloader.
PCI device addressing: Each PCI device has a domain:bus:device.function address (e.g., 0000:4f:00.0). The assistant uses these addresses to query individual device driver bindings through the Linux sysfs filesystem at /sys/bus/pci/devices/.
Output Knowledge Created
This message produces several critical pieces of knowledge:
- Negative confirmation: The vfio-pci binding is not configured through the kernel cmdline or modprobe.d, ruling out the two most common configuration methods.
- Positive confirmation: The vfio module stack is fully loaded and operational, with four devices actively bound.
- Scope confirmation: All five NVIDIA GPUs are uniformly bound to vfio-pci, with no exceptions.
- Architecture insight: The Proxmox host uses ZFS root (
root=ZFS=rpool/ROOT/pve-1) and boots via UEFI (initrd=\EFI\proxmox\...), which is relevant for understanding the boot process and where configuration might be stored. - Diagnostic direction: The absence of explicit configuration means the binding must be coming from either Proxmox's runtime VM management or from a configuration source not yet checked (such as Proxmox's
/etc/pve/directory or the LXC configuration files).
Assumptions and Potential Missteps
The assistant makes several implicit assumptions in this probe:
Assumption 1: The vfio-pci binding is configured through standard Linux mechanisms (kernel cmdline or modprobe.d). This is a reasonable starting point but may not hold in Proxmox environments where binding can be managed dynamically through the Proxmox VE API.
Assumption 2: The PCI addresses are stable and correctly identified. The assistant is using addresses discovered earlier in the session, but if the GPU topology changed during the migration (e.g., if GPUs were physically moved between PCIe slots), the addresses might be stale.
Assumption 3: The vfio_pci usage count of 4 corresponds to GPU devices. It's possible that some non-GPU devices (such as the audio functions of the NVIDIA cards) are also bound to vfio-pci, which would explain the discrepancy between the count of 4 and the 5 GPU addresses checked.
Potential misstep: The assistant does not check Proxmox's runtime state—specifically, whether any VMs are currently running with PCI passthrough. If VMs are running, they would hold the vfio-pci binding on the 3090s, and unbinding those GPUs would require stopping the VMs first. The assistant also doesn't check the LXC configuration for CT129 to see if it specifies GPU passthrough that might be conflicting.
The Path Forward
The results of this diagnostic probe set the stage for the next actions. The assistant now knows that:
- It cannot simply remove a modprobe configuration file to unbind the A6000s
- It needs to investigate Proxmox's VM configurations and runtime state
- It may need to manually unbind the A6000s from vfio-pci and rebind them to the NVIDIA driver
- It needs to ensure the 3090s remain bound to vfio-pci for their respective VMs The solution will likely involve either (a) modifying the Proxmox VM configurations to only bind the 3090s, then rebooting or reloading the vfio driver, or (b) using the
driverctltool or direct sysfs manipulation to override the driver binding for specific PCI addresses. The assistant's next message will need to check Proxmox's/etc/pve/configuration directory and the running VM state to determine the full picture.
Conclusion
Message 6767 is a textbook example of diagnostic debugging in a complex systems integration context. It demonstrates how a single, well-structured command can simultaneously test multiple hypotheses, eliminate dead ends, and narrow the search space. The assistant's methodical approach—checking the most likely configuration sources first, then confirming the scope of the problem through direct device inspection—reflects a deep understanding of Linux kernel driver architecture and Proxmox virtualization internals. The probe reveals not just the current state of the GPU bindings, but also the boundaries of the assistant's knowledge: it knows what it doesn't know, and the results point clearly to where the investigation must go next. In the high-stakes world of AI infrastructure deployment, where every minute of downtime translates to lost compute, this kind of efficient, targeted debugging is invaluable.