You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ubuntu 22 + QEMU KVM + OVMF 环境下无法按需在nvidia与vfio-pci间正确绑定/解绑GPU(无需重启)

Ubuntu 22 + QEMU KVM + OVMF 环境下无法按需在nvidia与vfio-pci间正确绑定/解绑GPU(无需重启)

我之前也碰到过几乎一模一样的问题,折腾了好几天才摸清楚门道,给你梳理下可能的原因和解决步骤:

一、核心问题拆解

1. 从VFIO切回nvidia后PyTorch失效的原因

虽然nvidia-smi能正常显示,但这只说明驱动加载成功了,PyTorch依赖的CUDA runtime没有正确初始化——VFIO接管设备时会重置GPU,切回nvidia驱动后,内核层面的CUDA上下文或设备状态没被彻底重置,导致PyTorch无法识别可用CUDA设备。

2. 从nvidia手动切到VFIO后VM报Error 43的原因

大概率是nvidia驱动没完全释放GPU的BAR内存,或是GPU的硬件状态(比如电源管理、显存锁定)还被nvidia驱动占用,导致QEMU无法正确映射BAR区域,触发Nvidia针对虚拟机的保护机制(Error 43)。


二、分场景解决步骤

场景1:从VFIO切回nvidia驱动,让PyTorch正常工作

  1. 先关闭所有VM,解绑VFIO设备:
    # 替换为你的GPU PCI地址,比如0000:01:00.0和0000:01:00.1
    echo 0000:01:00.0 > /sys/bus/pci/drivers/vfio-pci/unbind
    echo 0000:01:00.1 > /sys/bus/pci/drivers/vfio-pci/unbind
    
  2. 加载nvidia相关驱动模块(未自动加载时执行):
    modprobe nvidia nvidia_uvm nvidia_modeset nvidia_drm
    
  3. 强制重置CUDA runtime状态(关键步骤):
    # 杀掉所有占用GPU的进程
    pkill -9 python
    pkill -9 nvidia-smi
    # 重新初始化nvidia设备节点
    rm -rf /dev/nvidia*
    nvidia-smi -r
    
  4. 测试PyTorch:
    import torch
    print(torch.cuda.is_available())
    
    现在应该能正常返回True了。

场景2:从nvidia驱动切到VFIO,让VM正常启动不报错

  1. 杀掉所有使用GPU的进程,停掉桌面服务(如果是桌面环境):
    pkill -9 python
    systemctl stop display-manager
    pkill -9 nvidia*
    
  2. 解绑nvidia驱动的设备,并绑定到vfio-pci:
    echo 0000:01:00.0 > /sys/bus/pci/drivers/nvidia/unbind
    echo 0000:01:00.1 > /sys/bus/pci/drivers/nvidia/unbind
    # 绑定GPU和音频控制器到vfio-pci(替换为你的设备ID)
    echo 10de:2684 > /sys/bus/pci/drivers/vfio-pci/new_id
    echo 10de:22ba > /sys/bus/pci/drivers/vfio-pci/new_id
    
  3. 重置GPU的PCI状态,强制释放BAR内存:
    echo 1 > /sys/bus/pci/devices/0000:01:00.0/reset
    echo 1 > /sys/bus/pci/devices/0000:01:00.1/reset
    
  4. 现在启动VM,应该不会再出现Error 43和BAR映射失败的问题。

三、额外优化建议

  1. 写切换脚本替代开机绑定,实现按需切换(无需重启):
    比如switch-gpu-to-vfio.sh

    #!/bin/bash
    # 停桌面服务和占用GPU的进程
    systemctl stop display-manager
    pkill -9 python nvidia*
    # 解绑nvidia
    echo 0000:01:00.0 > /sys/bus/pci/drivers/nvidia/unbind
    echo 0000:01:00.1 > /sys/bus/pci/drivers/nvidia/unbind
    # 绑定vfio-pci
    echo 10de:2684 > /sys/bus/pci/drivers/vfio-pci/new_id
    echo 10de:22ba > /sys/bus/pci/drivers/vfio-pci/new_id
    # 重置GPU
    echo 1 > /sys/bus/pci/devices/0000:01:00.0/reset
    echo 1 > /sys/bus/pci/devices/0000:01:00.1/reset
    

    再写switch-gpu-to-nvidia.sh

    #!/bin/bash
    # 关闭VM(替换为你的VM名称)
    virsh shutdown win11-vm
    # 解绑vfio-pci
    echo 0000:01:00.0 > /sys/bus/pci/drivers/vfio-pci/unbind
    echo 0000:01:00.1 > /sys/bus/pci/drivers/vfio-pci/unbind
    # 加载nvidia模块
    modprobe nvidia nvidia_uvm nvidia_modeset nvidia_drm
    # 重置CUDA状态
    rm -rf /dev/nvidia*
    nvidia-smi -r
    # 重启桌面服务
    systemctl start display-manager
    

    记得给脚本加执行权限:chmod +x switch-gpu-*.sh

  2. 确保内核开启IOMMU相关参数:
    /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT中添加:

    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash iommu=pt vfio_iommu_type1.allow_unsafe_interrupts=1"
    

    然后更新grub:update-grub

备注:内容来源于stack exchange,提问作者SpacemanSanchez

火山引擎 最新活动