TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

GPU 直通与 vfio-pci:将整块 GPU 传递给虚拟机(VM)的原理

状态:草稿(2026-10-05),已反映实测结果。 「实测示例」一节中的数值是在一台 GPU 服务器上通过只读命令直接确认的,设备 ID 等识别信息已替换为占位符。原理说明基于内核与 KubeVirt 文档的内容,但在撰写本文时并未重新打开文档进行核对(未确认)。诸如内存锁定与崩溃循环之间的关系等未能验证的推测,均已明确标注。编写规则:以实测数据为基础,未能测得的内容标记为「未实测」。

目录

1. 为什么使用直通

为工作负载分配 GPU 的方法大致有四种。

方式 单位 隔离 与本文的关系
容器(device plugin) 整张 GPU 或分时复用 进程级别,与宿主机内核和驱动共享 第 3 篇
MIG 在硬件层面分割 GPU(仅限支持的模型) 硬件级别 第 3 篇
vGPU 由驱动创建的虚拟 GPU 由虚拟机监控程序管理,需要许可证 范围外
直通 整张物理 GPU 虚拟机独占设备 本文

需要使用直通的情况可以归纳为三种:当客机需要使用与宿主机不同的内核或驱动版本时,当客机操作系统不是 Linux 时,以及当需要容器无法满足的隔离性时。相反, 该 GPU 无法同时被宿主机和容器使用。 在本文后半部分,我们将实际看到同一设备在一端 nvidia-smi 运行失败的现象。

2. 原理:四个组件

直通是将设备的所属权从宿主机内核的通用驱动转移到用户空间进程(QEMU)的过程。为此,四个组件协同工作。

2.1 驱动绑定

PCI 设备拥有厂商 ID 和设备 ID(示例中的 GPU 为 10de:XXXX),内核会为其绑定一个匹配的驱动。通常情况下会绑定 nvidia 驱动,此时宿主机上的 nvidia-smi 即可正常工作。而在直通中,则会改用绑定 vfio-pci 。 vfio-pci 不是使用设备的驱动,而是将设备交予用户空间的中间驱动。绑定了该驱动的设备将不再由宿主机内核使用。

绑定方法有两种。一种是在运行时通过 driver_override 与 bind/unbind 进行切换,另一种是在启动时让 vfio-pci 优先抢占该 ID。示例服务器采用的是后者(第 3 节)。

2.2 IOMMU:将设备的内存访问范围限制在内的装置

GPU 通过 DMA 直接对系统内存进行读写。当把设备交给客机时,客机使用的内存地址与宿主机的实际地址不同,因此设备可能会访问到错误宿主机内存。 IOMMU 通过转换设备发出的 DMA 地址并限制其允许范围来解决这个问题。这是一种仅向设备开放客机内存区域的方式。

隔离的最小单位是 IOMMU 组。由于同一组中的设备无法将其 DMA 互相隔离开,因此组内的设备 必须全部移交给同一个所有者 。因此,GPU 的音频功能(示例中的 01:00.1)也需要一起绑定到 vfio-pci 中。

2.3 VFIO 接口

VFIO 是一项将设备安全暴露给用户空间的内核功能。用户空间进程通过打开 /dev/vfio/vfio(容器)和 /dev/vfio/<그룹 번호> 来执行以下操作:将设备的 BAR(内存区域)映射到自身的地址空间,将客机内存注册到 IOMMU,并通过事件文件描述符接收设备的中断并注入客机。QEMU 负责处理这些工作。

由于客机内存是 DMA 的目标,因此必须将其固定(pin),以防宿主机将其回收或交换出去。 这意味着拥有 12GiB 内存的虚拟机在启动时会固定 12GiB 的宿主机内存(根据文档所述,未进行直接测量)。

2.4 重置

虚拟机结束运行后,必须将设备恢复到干净的状态,以便下一个使用者安全使用。最好的方式是设备支持的 FLR(Function Level Reset),如果不支持则使用总线重置。无法正常重置的 GPU 会导致虚拟机使用一次后必须重启宿主机的问题。

3. 实测示例:将 6GB 级 GPU 传递给一台服务器

所有数值均通过只读命令确认,每台设备的 示例值各不相同。宿主机内核为 7.0.0-34-generic。设备 ID 已用 XXXX(GPU)和 YYYY(音频)隐去。

项目 值 含义
lspci -nnk -d 10de: 01:00.0 GPU(10de:XXXX)与 01:00.1 音频(10de:YYYY)均由 Kernel driver in use: vfio-pci 两个功能均由 vfio-pci 拥有
IOMMU 组 组 16,成员仅有 01:00.0 和 01:00.1 两个 由于组很干净,可以单独将此 GPU 传递出去
内核命令行 iommu 无相关参数,但 IOMMU 组有 20 个 在此内核中,IOMMU 默认处于开启状态
已加载模块 vfio_pci, vfio_pci_core, vfio_iommu_type1, vfio, kvm_intel VFIO 栈已加载
/dev/vfio/ 16(组设备)与 vfio(容器) 准备好交予用户空间的状态
reset_method flr bus 支持 FLR,否则使用总线重置
BAR 区域 区域 0 为 16M,区域 1 为 8G(可预取),区域 3 为 32M 会将 GPU 的内存窗口映射到客机
PCIe 链路 能力 16GT/s x16,当前 16GT/s x8 (downgraded) 链路宽度已降低至一半

链路宽度降低至 x8 的原因尚未确认。可能是由于主板布线或电源状态导致的,因此不作定论。

3.1 配置文件

在本示例中,用于实现直通的配置文件有两个。

# /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

示例服务器的启动镜像(initramfs)中没有 vfio 项。因此,此配置仅靠文件即可生效而无需重新生成镜像,还原时也只需出于同样的原因清理文件即可(不过尚未测试重启后是否确实能恢复原状)。

4. 同一设备上 nvidia-smi 失败的原因

在此宿主机上执行 nvidia-smi 时,会出现「无法与 NVIDIA 驱动通信」的提示。这并不意味着未安装驱动。宿主机上已安装 nvidia-driver-595-open(595.91.07),并且也有当前内核对应的模块软件包。

内核日志直接揭示了原因。

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

nvidia 每当 vfio-pci 模块试图接管设备时,都会反复打印已经被 nvidia-smi 拥有的消息。由于绑定到设备的驱动只有一个,因此当所有权归属 VFIO 时,宿主机的 没有可通信的对象。这不是故障,而是符合配置的正常行为

。

Kubernetes 侧的状态也说明了这一点。 位置
值 nvidia.com/gpu 0 节点
(没有可供容器使用的 GPU) nvidia.com/<모델별 자원 이름> 1 节点
(有可供虚拟机使用的设备) nvidia.com/gpu.deploy.operands false 节点标签
(GPU Operator 组件已关闭) driver.enabled false GPU Operator

(使用宿主机安装的驱动的配置)

  1. 5. KubeVirt 将设备连接到虚拟机的途径 permittedHostDevices 在 KubeVirt 配置的 pciVendorSelector: 10DE:XXXX 中注册了 resourceName: nvidia.com/<모델별 자원 이름> 和 HostDevices ,并且开启了功能门槛(feature gate)
  2. 。节点的 virt-handler 查找该 ID 的设备并将其作为 Kubernetes 扩展资源进行通告。其结果就是上表中的 nvidia.com/<모델별 자원 이름>: 1 。
  3. 在虚拟机定义的 devices.gpus 中写入 deviceName: nvidia.com/<모델별 자원 이름> 。调度器仅将虚拟机放置在拥有此资源的节点上。
  4. 虚拟机启动时,QEMU 通过 VFIO 打开相应的 IOMMU 组并将设备连接到客机。

这里重要的一点是, 资源名称使用的不是 nvidia.com/gpu 而是单独的名称。容器用 GPU 和虚拟机用 GPU 是不同的资源,一张 GPU 只能以其中一种形式进行通告。

6. 常见陷阱:内存锁定与宿主机 OOM

如 2.3 节所述,直通了 GPU 的虚拟机将其客机内存固定在宿主机中。由于被固定的内存无法通过交换(swap)释放,因此在虚拟机启动的瞬间,就需要一次性消耗相当于客机大小的宿主机内存。如果同一宿主机上还在运行其他工作负载和节点守护进程,总内存很容易超出物理内存。

当宿主机整体内存不足时,内核的 OOM killer 就会启动。此时内核日志中记录的不是容器超限(Memory cgroup out of memory),而是宿主机整体内存不足(Out of memory: Killed process)。牺牲者不仅可能是虚拟机进程(qemu-kvm),还可能是节点的系统守护进程。如果虚拟机在崩溃后重新启动,就会陷入不断重复相同情况的崩溃循环(crash loop),而守护进程在此期间也会持续不断地一同死去。

笔者在实验环境中观察到的宿主机 OOM 日志与此流程一致。不过,由于未实际测量虚拟机启动时实际固定的内存大小,该解释仅为 推测(未实测)。教训有两点:在宿主机内存不富裕的服务器上最好不要部署多台 GPU 虚拟机;在启动虚拟机之前,应先将客机内存总和与宿主机已使用的内存相加进行评估。

7. 常态化恢复为容器用 GPU(示例步骤)

解除直通并将设备恢复为容器使用,最简单的方法是排空节点(cordon、drain)、清理配置文件然后重启。但如果该节点上还运行着其他服务,重启将是一项会中断所有服务的重大操作。以下是 不重启而仅传递设备 的示例。判定其可行的依据均已通过只读方式预先确认。

事前确认 结果
/dev/vfio/<그룹 번호> 占用 的进程
无 使用 GPU 的虚拟机
无 设备状态 flr bus 空闲,支持重置方式
nvidia 模块 595.91.07,当前内核可用,已签名

首先备份并清理两个配置文件,然后执行以下两个步骤。

# 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

结果。 unbind 之后不久,设备的驱动变更为 nvidia 且 nvidia-smi 恢复正常运作。

项目 值
GPU 6GB 级笔记本 GPU,6,144MiB
驱动 595.91.07
lspci 01:00.0 的 Kernel driver in use: nvidia
宿主机 运行时间保持不变,负载无变化,对其他服务无影响

需要同时注意的一点。

若要还原,只需将 driver_override 改为 vfio-pci 并解除 nvidia 即可。在此转换之后,GPU VM 将无法使用此 GPU。 若要让容器和虚拟机交替使用单张 GPU,每次都需要进行此转换,因此在数量较少的环境中,必须明确指定其用途。

8. 面试可能出现的问题

9. 常见误解

外部依据:直通的性能开销

由于无法直接测量直通 VM 的性能,我们查阅了针对相同问题的外部资料。能够打开的范围包括摘要、厂商文章和部分原文。

资料 确认的内容与条件 可靠性与局限性
Walters 等人,“GPU Passthrough Performance: A Comparison of KVM, Xen, VMWare ESXi, and LXC for CUDA and OpenCL Applications”,IEEE CLOUD 2014 摘要:KVM 直通达到裸金属的 98~100%,Xen 和 VMware 达到 96~99%(两代 GPU,两种处理器微架构) 同行评议论文或正文无法打开,因此 IOMMU、大页面、NUMA、链路宽度条件未知。2014 年 GPU
Steininger 等人,“GPU Passthrough Across Virtualization Platforms for LLM Inference”,Computers (MDPI) 第 15 卷,2026 摘要:将一张工作站级 GPU 直通到 Proxmox VM·LXC、KVM、OpenStack、Podman,vLLM 小型模型的吞吐量和词元间延迟在所有平台上均在裸金属的 2% 以内(统计学上等效) 作者说明这并非普遍结论。设备未饱和的区域。由于无法访问正文,仅确认了摘要
OpenNebula 厂商博客 (2026-03-18) GB200 NVL4 直通 cuBLAS GEMM 71,891 对比 71,738 GFLOP/s(相差 0.21%),vLLM 吞吐量在 ±4% 以内 厂商文章,未明确说明 NUMA 绑定、大页面、IOMMU 配置
VMware 性能研究 (2023-10) 在 vGPU(完整配置文件 H100)下,GPT-J 6B 达到裸金属的 97.9~99.8%(MLPerf 推理 v3.1) 并非直通,而是 vGPU。未经 MLCommons 验证的结果
Samani, Amini Salehi, arXiv 2112.09780, 2021 比较了裸金属、VM(直通)和容器。没有一致的单一开销,端到端推理时间受 CPU 预处理和存储 I/O 的支配,GPU 部分的影响很小。如果主机上没有空闲核心,VM 开销会增加,而 CPU 绑定可减少该开销 Tesla K40,2 插槽 80 核,HDD。较旧的 GPU
NVIDIA CUDA Programming Guide 3.4.2.5, NCCL GPU troubleshooting 说明在裸金属中应关闭 IOMMU,而在 VM 直通中应开启 IOMMU 并使用 VFIO。ACS 会将 P2P 绕道至 CPU 根联合体,从而大大降低带宽,而 VM 无法关闭 ACS,若要在 VM 内部获得最高性能,则需要网卡的 ATS 官方文档。在单 GPU 服务器中,P2P 不是关键问题

未确认的事项

参考资料

确认的版本和日期

截至 2026-10-05。主机内核 7.0.0-34-generic,NVIDIA 驱动程序包 595.91.07(安装在主机上),使用 KubeVirt HostDevices 功能门。

登录后即可点赞

评论

还没有评论。

登录后即可发表评论