这份文档基于一次完整的实战排障过程整理,目标是:在 Proxmox VE 宿主机上启用 Intel 核显 SR-IOV,将一个 VF 直通给飞牛 fnOS 虚拟机,并最终让飞牛视频服务成功使用 GPU 解码/转码。但是系统显示的不太对,这个无所谓了。
TL;DR
Intel i3-12100 的显卡通过 SR-IOV 拆分出了 3 个 VF,把第三个 VF 分配给飞牛的 vm。

飞牛影视中正常开启 GPU 加速

视频中使用 GPU 加速

资源利用率 OK,如果用 CPU 的话 CPU 早爆了

注:下面的这些部分是基于我和 chatgpt 5.4 对话解决问题过程中总结的部分,可以丢给你的 AI Agent 让他一步步指导你。
目录
- 适用范围与最终目标
- 正确架构:PF 留给宿主机,VF 给虚拟机
- PVE 宿主机前提条件
- PVE 宿主机配置步骤
- 把 VF 绑定到 vfio-pci
- 宿主机验证
- 飞牛 VM 配置
- 飞牛 guest 内安装 i915-sriov-dkms
- 飞牛 guest 内验证 GPU / VAAPI
- 飞牛视频服务的权限与应用层问题
- ffmpeg / libva ABI 冲突的处理
- 本次排障中踩过的坑
- 最终检查清单
1. 适用范围与最终目标
适用于以下场景:
- 宿主机:
Proxmox VE
- GPU:Intel 核显,支持通过
strongtz/i915-sriov-dkms 实现 SR-IOV
- 客体:飞牛 fnOS(Linux guest)
- 目标:给飞牛分配一个
VF,并让飞牛视频服务能使用 GPU 解码/转码
最终成功标志:
- 宿主机上
00:02.0 由 i915 驱动
- 宿主机上
00:02.1 ~ 00:02.x 由 vfio-pci 驱动
- 飞牛 guest 内有
/dev/dri/renderD128
vainfo --display drm --device /dev/dri/renderD128 正常
- 飞牛媒体服务可正常使用 GPU
2. 正确架构:PF 留给宿主机,VF 给虚拟机
这是整套方案里最重要的原则。
| 功能 |
应该给谁 |
00:02.0(PF,主功能) |
宿主机 PVE 自己使用,由 i915 驱动 |
00:02.1 / 00:02.2 / 00:02.3 ...(VF) |
分配给虚拟机,通过 vfio-pci 直通 |
绝对不要把 00:02.0 这个 PF 直通给飞牛。
这样会把宿主机自己的核显主功能拔走,导致 SR-IOV 状态混乱、VM 启动卡死、8006 掉线,甚至宿主机整体失联。
3. PVE 宿主机前提条件
- BIOS 中开启 VT-d / Intel IOMMU
- PVE 已安装并正常启动
- 已安装
i915-sriov-dkms 对应版本
- 确认你的核显设备 ID,例如本次为
8086:4692(Alder Lake-S UHD 730)
可先查看设备:
lspci -nn | grep -i 'vga\|display'
4. PVE 宿主机配置步骤
4.1 调整 GRUB 启动参数
宿主机最终采用 i915 路线,而不是 xe 路线。
cp /etc/default/grub /etc/default/grub.bak.$(date +%F-%H%M%S)
sed -i 's#^GRUB_CMDLINE_LINUX_DEFAULT=.*#GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on i915.enable_guc=3 i915.max_vfs=3 module_blacklist=xe"#' /etc/default/grub
grep '^GRUB_CMDLINE_LINUX_DEFAULT' /etc/default/grub
不要保留这些旧参数:
xe.max_vfs=...
xe.force_probe=...
module_blacklist=i915
i915.force_probe=${device_id} 这种未展开变量
4.2 固定 VF 数量
apt-get install -y sysfsutils || true
grep -q 'devices/pci0000:00/0000:00:02.0/sriov_numvfs' /etc/sysfs.conf 2>/dev/null \
&& sed -i 's#^devices/pci0000:00/0000:00:02.0/sriov_numvfs = .*#devices/pci0000:00/0000:00:02.0/sriov_numvfs = 3#' /etc/sysfs.conf \
|| echo 'devices/pci0000:00/0000:00:02.0/sriov_numvfs = 3' >> /etc/sysfs.conf
cat /etc/sysfs.conf
4.3 更新引导与 initramfs
update-grub
update-initramfs -u -k all
proxmox-boot-tool refresh
5. 把 VF 绑定到 vfio-pci
目标:宿主机保留 PF,VF 全部交给 vfio-pci,避免宿主机图形栈误占用 VF。
5.1 确保 vfio-pci 开机加载
echo "vfio-pci" >/etc/modules-load.d/vfio.conf
touch /etc/initramfs-tools/modules
grep -qxF 'vfio-pci' /etc/initramfs-tools/modules || echo 'vfio-pci' >> /etc/initramfs-tools/modules
5.2 写 udev 规则绑定 VF
cat >/etc/udev/rules.d/99-i915-vf-vfio.rules <<'EOF'
ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:00:02.[1-3]", ATTR{vendor}=="0x8086", ATTR{device}=="0x4692", DRIVER!="vfio-pci", RUN+="/bin/sh -c 'if [ -L /sys/bus/pci/devices/\$kernel/driver ]; then echo \$kernel > /sys/bus/pci/devices/\$kernel/driver/unbind; fi; echo vfio-pci > /sys/bus/pci/devices/\$kernel/driver_override; modprobe vfio-pci; echo \$kernel > /sys/bus/pci/drivers/vfio-pci/bind'"
EOF
5.3 重建 initramfs
update-initramfs -u -k all
proxmox-boot-tool refresh
本次配置里只创建了 3 个 VF,所以规则匹配的是 00:02.1 ~ 00:02.3。如果你后续改成更多 VF,要同步改规则和 i915.max_vfs。
6. 宿主机验证
重启宿主机后检查:
cat /proc/cmdline
lspci -nnk -s 00:02
lspci -nn | grep -E '00:02\.[1-3]'
ls -l /dev/dri
预期结果:
/proc/cmdline 含有:intel_iommu=on i915.enable_guc=3 i915.max_vfs=3 module_blacklist=xe
00:02.0 的 Kernel driver in use 是 i915
00:02.1 / 00:02.2 / 00:02.3 的 Kernel driver in use 是 vfio-pci
/dev/dri 只保留宿主机的 card0 和 renderD128
7. 飞牛 VM 配置
7.1 正确直通 VF
不要传 PF,只传 VF,例如:
qm set 108 --hostpci0 0000:00:02.3,pcie=1
7.2 关闭 vIOMMU
本次排障中,VM 启动时报过:
vfio 0000:00:02.3: Failed to set vIOMMU: aw-bits 48 > host aw-bits 39
根因是 VM 配置里有:
machine: q35,viommu=intel
修复方法:
qm set 108 --machine q35
也就是把 viommu=intel 去掉,只保留 machine: q35。
7.3 一个可工作的示例配置
agent: 1
bios: ovmf
boot: order=scsi0
cores: 2
cpu: host
efidisk0: extra:vm-108-disk-0,efitype=4m,pre-enrolled-keys=1,size=1M
hostpci0: 0000:00:02.3,pcie=1
ide2: extra:vm-108-cloudinit,media=cdrom
machine: q35
memory: 4096
name: fnOS
net0: virtio=...,bridge=vmbr0,firewall=1
numa: 0
ostype: l26
scsi0: extra:vm-108-disk-1,iothread=1,size=64G,ssd=1
scsi1: extra:vm-108-disk-2,iothread=1,size=64G,ssd=1
scsihw: virtio-scsi-single
sockets: 1
vga: none
8. 飞牛 guest 内安装 i915-sriov-dkms
这是 guest 内最关键的一步。宿主机 SR-IOV 正常,并不代表飞牛 guest 自己能驱动这个 VF。guest 内同样需要安装 i915-sriov-dkms。
8.1 先装依赖
apt update
apt install -y dkms build-essential pciutils vainfo git
apt install -y linux-headers-$(uname -r)
8.2 安装 guest 侧 DKMS 模块
你可以用已下载好的对应版本包,也可以自己通过源码安装。关键是版本要和内核兼容。
8.3 guest 内核参数
guest 最终采用:
i915.enable_guc=3 module_blacklist=xe
本次成功后的 /proc/cmdline 类似:
BOOT_IMAGE=/boot/vmlinuz-6.12.18-trim root=UUID=... ro modprobe.blacklist=pcspkr pcie_aspm=off quiet pcie_aspm=off i915.enable_guc=3 module_blacklist=xe
注意: guest 侧不需要再加宿主机用的 intel_iommu=on、i915.max_vfs=... 这些参数。VF 数量由宿主机控制。
9. 飞牛 guest 内验证 GPU / VAAPI
9.1 先看设备与驱动
lspci -nnk | grep -A3 -i 'VGA\|Display'
dmesg | grep -iE 'i915|xe|drm|firmware'
ls -l /dev/dri
成功标志:
Kernel driver in use: i915
Running in SR-IOV VF mode
- 出现
/dev/dri/renderD128
9.2 验证 VAAPI
vainfo --display drm --device /dev/dri/renderD128
如果输出中能看到各种 profile,例如:
VAProfileH264High
VAProfileHEVCMain10
VAProfileVP9Profile0
VAProfileAV1Profile0
说明 VAAPI 本身已经可用。
10. 飞牛视频服务的权限与应用层问题
10.1 把运行用户加入 video 和 render
设备权限通常是:
crw-rw---- 1 root video ...
crw-rw---- 1 root render ...
如果飞牛的登录用户或媒体服务用户不在这些组里,即使 GPU 和 VAAPI 都好了,应用也用不了。
usermod -aG video fn
usermod -aG render fn
执行后需要重新登录会话,再看:
groups
id
预期:
Users video render Administrators
10.2 如果媒体服务不是用 fn 跑的
那应该把真正运行媒体服务的用户加进 video / render,不是只加登录用户。
11. ffmpeg / libva ABI 冲突的处理
这是本次配置里最后一个难点。
现象:
[AVHWDeviceContext] ... iHD_drv_video.so has no function __vaDriverInit_1_0
这说明不是 GPU 不通,而是 ffmpeg 使用的 VAAPI 用户态栈和驱动 ABI 不匹配。
在本次飞牛环境里,vainfo 实际使用的是:
/usr/trim/lib/mediasrv/dri/iHD_drv_video.so
因此需要让应用继承这两个环境变量:
export LIBVA_DRIVER_NAME=iHD
export LIBVA_DRIVERS_PATH=/usr/trim/lib/mediasrv/dri
在某些场景下,还需要补:
export LD_LIBRARY_PATH=/usr/trim/lib/mediasrv:$LD_LIBRARY_PATH
经验结论:
如果 vainfo 能通,而应用内 GPU 不工作,优先怀疑:
- 运行用户没有权限
- 应用没有继承正确的
LIBVA_* 环境
- 应用使用了另一套旧的
ffmpeg / libva 栈
12. 本次排障中踩过的坑
-
把 PF 00:02.0 直通给飞牛
这是最危险的错误,会导致宿主机 i915/SR-IOV 状态混乱,甚至宿主机启动 VM 时失联。
-
宿主机仍保留 xe 时代的旧参数
例如 xe.max_vfs、module_blacklist=i915。需要完全清理。
-
VM 开了 vIOMMU
导致 Failed to set vIOMMU: aw-bits 48 > host aw-bits 39,应去掉 viommu=intel。
-
只在宿主机装了 i915-sriov-dkms,没有在 guest 装
这样 guest 内通常只能看到 PCI 设备,但 i915 probe 失败,没有 /dev/dri。
-
用户不在 video / render 组
导致 VAAPI 设备节点存在,但应用访问不到。
-
vainfo 成功,却误以为 ffmpeg 一定也会成功
实际上 ffmpeg 可能使用了另一套不兼容的 libva/驱动路径。
13. 最终检查清单
# 宿主机
cat /proc/cmdline
lspci -nnk -s 00:02
ls -l /dev/dri
# VM 配置
qm config 108
# 飞牛 guest
cat /proc/cmdline
lspci -nnk | grep -A3 -i 'VGA\|Display'
dmesg | grep -iE 'i915|xe|drm|firmware'
ls -l /dev/dri
groups
id
vainfo --display drm --device /dev/dri/renderD128
通过标准:
- 宿主机 PF 是
i915,VF 是 vfio-pci
- VM 只直通 VF,不直通 PF
- VM 配置里没有
viommu=intel
- 飞牛内有
/dev/dri/renderD128
- 飞牛内
vainfo 正常
- 飞牛运行用户在
video / render 组
- 飞牛视频服务使用正确的 VAAPI 用户态环境
这份文档基于一次完整成功的实战整理,已经覆盖宿主机、VF 绑定、飞牛 guest 驱动、权限、VAAPI 验证以及 ffmpeg/libva ABI 冲突等关键细节。后续如果你更换内核、升级 fnOS 或改 VF 数量,记得同步检查 GRUB、udev 规则、guest DKMS 版本以及应用层环境变量。