TT Lab
Blog

한국어 English 日本語 中文

Get started
Blog

Blog

GPU Passthrough and vfio-pci: The Principle of Handing Over a GPU Entirely to a VM

Status: Draft (2026-10-05), reflecting actual measurements. The values in the "Actual Measurement Example" section were directly verified using read-only commands on a single GPU server, and identification information such as device IDs has been replaced with placeholders. The explanation of the principles is based on kernel and KubeVirt documentation, which was not re-opened and cross-checked at the time of writing this post (unverified). Unverified assumptions, such as the relationship between memory pinning and crash loops, are marked as such. Writing rule: Actual measurement data is the default, and anything that could not be measured is marked as "Unmeasured".

Table of Contents

1. Why Use Passthrough

There are broadly four ways to provide a GPU to a workload.

Method Unit Isolation Relationship to This Post
Container (device plugin) Single GPU or time-sliced Process level, shares host kernel and drivers Part 3
MIG Hardware-partitioned GPU (supported models only) Hardware level Part 3
vGPU Virtual GPU created by driver Managed by hypervisor, requires license Out of scope
Passthrough Entire physical GPU VM exclusively owns the device This post

The scenarios requiring passthrough narrow down to three: when the guest needs a different kernel or driver version than the host, when the guest OS is not Linux, and when isolation stronger than what containers can offer is required. Instead, that GPU cannot be used simultaneously by the host and containers. Later in this post, we will actually see the same device nvidia-smi failing on one side.

2. Principles: Four Components

Passthrough is the process of transferring device ownership from a general host kernel driver to a user-space process (QEMU). Four components work together to achieve this.

2.1 Driver Binding

PCI devices have a vendor ID and a device ID (for example, the GPU has 10de:XXXX), and the kernel attaches a single driver matching that ID. Normally, the nvidia driver is attached, and then nvidia-smi runs on the host. In pass-through, vfio-pci is attached instead. vfio-pci is not a driver that uses the device, but an intermediary driver that hands the device over to user space. A device with this driver attached is not used by the host kernel.

There are two ways to attach it. One is to switch it at runtime using driver_override and bind/unbind, and the other is to have vfio-pci claim the corresponding ID first at boot time. The example server uses the latter method (Section 3).

2.2 IOMMU: A Device That Restricts Device Memory Access

The GPU reads from and writes to system memory directly via DMA. When the device is given to the guest, the memory addresses used by the guest differ from the actual addresses of the host, so the device could touch unintended host memory. IOMMU translates the DMA addresses generated by the device and restricts the allowed rangeto prevent this issue. This is done by opening only the guest memory region to the device.

The minimum unit of isolation is the IOMMU group. Since devices belonging to the same group cannot isolate each other's DMA, all devices in the group must be handed over to the same owner . Therefore, the GPU's audio function (the 01:00.1in the example) is also bound together to vfio-pci .

2.3 VFIO Interface

VFIO is a kernel feature that safely exposes devices to user space. A user-space process opens /dev/vfio/vfio(container) and /dev/vfio/<그룹 번호> to do the following: map the device's BAR (memory region) into its own address space, register guest memory with the IOMMU, and receive the device's interrupts via event file descriptors to inject them into the guest. QEMU performs these tasks.

Since guest memory is the target of DMA, it must be pinned so that the host cannot reclaim or swap it out. A VM with 12GiB of memory means that 12GiB of host memory is pinned upon startup (based on documentation, not directly measured).

2.4 Reset

When a VM terminates, the device must be returned to a clean state for the safety of the next user. The best method is FLR (Function Level Reset) supported by the device, and if not supported, a bus reset is used. GPUs that do not reset properly cause an issue where the host must be rebooted after using the VM once.

3. Measurement Example: A server passing through a 6GB-class GPU

These values were all checked using read-only commands and are example valuesthat vary by equipment. The host kernel is 7.0.0-34-generic. The device IDs are masked as XXXX(GPU) and YYYY(audio).

Item Value Meaning
lspci -nnk -d 10de: 01:00.0 GPU(10de:XXXX) and 01:00.1 audio(10de:YYYY) both Kernel driver in use: vfio-pci Both features vfio-pci is owned by
IOMMU group Group 16, members are just 01:00.0 and 01:00.1 only The group is clean so this GPU can be passed through separately
Kernel command line iommu related arguments none, but there are 20 IOMMU groups In this kernel, IOMMU is enabled by default
Loaded modules vfio_pci, vfio_pci_core, vfio_iommu_type1, vfio, kvm_intel VFIO stack is up
/dev/vfio/ 16(group device) and vfio(container) Ready to be handed over to user space
reset_method flr bus Supports FLR, falls back to bus reset if not supported
BAR regions Region 0 is 16M, Region 1 is 8G (prefetchable), Region 3 is 32M The GPU's memory window will be mapped to the guest
PCIe link capability 16GT/s x16, current 16GT/s x8 (downgraded) link width has dropped by half

The cause for the link width dropping to x8 could not be verified. Since it could be due to board wiring or power states, no definitive conclusion is made.

3.1 Configuration files

In this example, the setup that creates the passthrough consists of two files.

# /etc/modprobe.d/vfio-gpu.conf
options vfio-pci ids=10de:XXXX,10de:YYYY
softdep nvidia pre: vfio-pci
softdep nouveau pre: vfio-pci
softdep snd_hda_intel pre: vfio-pci

# /etc/modules-load.d/vfio-pci.conf
vfio-pci

The example server's boot image (initramfs) did not contain a single vfio entry. Therefore, this configuration works purely with files without requiring an image regeneration, and it can be reverted for the same reason by removing the files (though it has not yet been tested whether it actually reverts after a reboot).

4. Why nvidia-smi fails on the same device

Running nvidia-smi on this host outputs a message saying "Failed to initialize NVML: Driver/library version mismatch" or that it cannot communicate with the NVIDIA driver. This does not mean the driver is not installed. The host has nvidia-driver-595-open(595.91.07) installed, along with the module package for the current kernel.

The kernel logs show the cause clearly.

NVRM: GPU 0000:01:00.0 is already bound to vfio-pci.

nvidia Every time the module attempts to claim the device, a message repeatedly appears stating that it is already owned by vfio-pci . Since there is only one driver attached to the device, the host's nvidia-smi has nothing to communicate with while ownership is held by VFIO. This is not a malfunction, but normal operation as configured.

The Kubernetes side status tells the same story.

Location Value
Node nvidia.com/gpu 0 (No GPU to give to containers)
Node nvidia.com/<모델별 자원 이름> 1 (Device available to give to VM)
Node label nvidia.com/gpu.deploy.operands false (GPU Operator components disabled)
GPU Operator driver.enabled false (Configuration using the driver installed on the host)

5. How KubeVirt connects a device to a VM

  1. In the KubeVirt configuration, permittedHostDevices and pciVendorSelector: 10DE:XXXX are registered under resourceName: nvidia.com/<모델별 자원 이름> , and the feature gate HostDevices is enabled.
  2. The node's virt-handler finds the device with that ID and advertises it as a Kubernetes extended resource. The result is the nvidia.com/<모델별 자원 이름>: 1 in the table above.
  3. Write the devices.gpus in the VM definition to deviceName: nvidia.com/<모델별 자원 이름> . The scheduler places the VM only on nodes that have this resource.
  4. When the VM starts, QEMU opens the corresponding IOMMU group via VFIO and attaches the device to the guest.

The important point here is that a separate name is used for the resource name, nvidia.com/gpu not. GPUs for containers and GPUs for VMs are different resources, and a single GPU is advertised as only one of the two.

6. Common Pitfall: Memory Pinning and Host OOM

A VM passed through a GPU pins its guest memory to the host, as described in Section 2.3. Since pinned memory cannot be absorbed by swap, the host needs an amount of memory equal to the guest size all at once the moment the VM starts. If other workloads and node daemons are running together on the same host, the total easily exceeds the physical memory.

If the host as a whole runs out of memory, the kernel's OOM killer activates. At this time, the kernel log records a host-wide out-of-memory error (Memory cgroup out of memory), not a container limit exceeded error (Out of memory: Killed process). The victim may not only be the VM process (qemu-kvm) but also a system daemon of the node. If the VM dies and restarts, it becomes a crash loop repeating the same thing, while the daemons also continue to die along with it.

The host OOM logs observed in the author's experimental environment matched this flow. However, since the actual pinned memory size was not measured when the VM started, this interpretation is an estimate(unmeasured). There are two lessons: it is safer not to place multiple GPU VMs on a server where host memory is not ample, and before bringing up a VM, you should first add up the sum of the guest memory and the memory already used by the host.

7. Reverting to Container GPUs (Example Procedure)

The simplest way to unbind passthrough and revert the device for containers is to cordon and drain the node, clear the configuration files, and reboot. However, if other services are running on that node, a reboot becomes a major operation that takes everything down. Below is an example of transferring only the device without a reboot . The basis for determining that this was possible was first verified entirely in read-only mode.

Pre-check Result
/dev/vfio/<그룹 번호> Processes holding the None
VMs using the GPU None
Device status Idle, reset method flr bus supported
nvidia Module 595.91.07, for current kernel, signed

First, we backed up two configuration files, removed them, and executed the following two steps.

# 1) 이 장치는 nvidia 드라이버로만 붙도록 지정한다.
echo nvidia | sudo tee /sys/bus/pci/devices/0000:01:00.0/driver_override
# 2) vfio-pci 에서 푼다. 풀리는 즉시 nvidia 가 장치를 가져간다.
echo 0000:01:00.0 | sudo tee /sys/bus/pci/drivers/vfio-pci/unbind

Result. unbind Immediately afterwards, the device driver changed to nvidia and nvidia-smi operated.

Item Value
GPU 6GB class laptop GPU, 6,144 MiB
Driver 595.91.07
lspci 01:00.0 's Kernel driver in use: nvidia
Host Uptime maintained, no load change, no impact on other services

Points to note together.

To revert, change driver_override to vfio-pci and release nvidia . After this switch, GPU VMs cannot use this GPU. If a single GPU must be shared alternately between containers and VMs, this switch must be performed every time,so in environments with a small number of GPUs, the use case must be fixed to one.

8. Potential Interview Questions

9. Common Misconceptions

External Evidence: Performance Overhead of Passthrough

Since we could not directly measure the performance of the passthrough VM, we checked external materials that measured the same question. The accessible scope includes abstracts, vendor articles, and some original texts.

Source Verified Content and Conditions Reliability and Limitations
Walters et al., "GPU Passthrough Performance: A Comparison of KVM, Xen, VMWare ESXi, and LXC for CUDA and OpenCL Applications", IEEE CLOUD 2014 Abstract: KVM passthrough achieves 98-100% of bare metal, Xen and VMware achieve 96-99% (two generations of GPUs, two processor microarchitectures) Peer-reviewed paper or main text could not be accessed, so IOMMU, huge pages, NUMA, and link width conditions are unknown. 2014 GPU
Steininger et al., "GPU Passthrough Across Virtualization Platforms for LLM Inference", Computers (MDPI) Vol. 15, 2026 Abstract: Passing through a single workstation-class GPU across Proxmox VM/LXC, KVM, OpenStack, and Podman results in vLLM small model throughput and inter-token latency within 2% of bare metal across all platforms (statistically equivalent) Authors state this is not a general claim. Tested in a region that does not saturate the device. Only the abstract was verified due to denied access to the main text
OpenNebula Vendor Blog (2026-03-18) GB200 NVL4 passthrough cuBLAS GEMM 71,891 vs 71,738 GFLOP/s (0.21% difference), vLLM throughput within ±4% Vendor article; NUMA pinning, huge pages, and IOMMU configurations are not specified
VMware Performance Study (2023-10) GPT-J 6B achieves 97.9-99.8% of bare metal with vGPU (full profile H100) (MLPerf Inference v3.1) vGPU rather than passthrough. Results not verified by MLCommons
Samani, Amini Salehi, arXiv 2112.09780, 2021 Comparison of bare metal, VM (passthrough), and container. There is no consistent single overhead; end-to-end inference time is dominated by CPU preprocessing and storage I/O, making the GPU portion's impact minor. If there are no idle cores on the host, VM overhead increases, which CPU pinning mitigates Tesla K40, 2-socket 80-core, HDD. Aging GPU
NVIDIA CUDA Programming Guide 3.4.2.5, NCCL GPU troubleshooting States to disable IOMMU on bare metal and enable IOMMU and use VFIO for VM passthrough. ACS bypasses P2P to the CPU root complex, significantly reducing bandwidth; VMs cannot disable ACS, and maximizing performance inside a VM requires network adapter ATS Official documentation. P2P is not an issue on single-GPU servers

Unverified Items

References

Verified Version and Date

As of 2026-10-05. Host kernel 7.0.0-34-generic, NVIDIA driver package 595.91.07 (installed on host), KubeVirt HostDevices feature gate enabled.

Sign in to like

Comments

No comments yet.

Sign in to leave a comment