安装NVIDIA Linux驱动

Nvidia Tesla P10 GPU运算卡 的GPU核心是Tesla,属于 Pascal 微架构

BIOS设置

以下是两种安装方式(互斥,选择其中之一即可):

CUDA软件堆栈(不同层次)

NVIDIA将GPU驱动和开发组件(Toolkits)分别组合成 cuda-driverscuda ,其中 cuda-driverscuda 的子集。由于虚拟化和容器化技术的发展,我们可以在不同的层次分别安装:

  • 物理主机: cuda-drivers

  • 虚拟机(PassThrough GPU):

    • 直接在虚拟机内运行应用及开发: cuda

    • 虚拟机内通过容器运行应用及开发:

      • 虚拟机: cuda-drivers

      • 容器: cuda

  • (裸金属)容器: cuda

简而言之,只有实际运行应用及开发的 主机/虚拟化/容器 层才需要完整安装 cuda ,其他作为支持层的层只需要安装 cuda-dirvers ,通过这种模式,可以构建 GPU Kubernetes

手工下载本地run安装(和发行版无关)

备注

我虽然下载了 .run 安装包,不过NVIDIA对主流发行版(RedHat/CentOS/Ubuntu/Debian/SUSE/OpenSUSE)都提供了软件仓库方式安装。并且经过验证,可以看到软件仓库提供了更新的安装包,而官方网站提供的下载驱动版本略微滞后。所以,我最终实践还是直接在Ubuntu 22.04上采用官方软件仓库,见下文。

../../../_images/tesla_p10_driver.png

驱动版本

Tesla P10驱动

版本

515.65.01

发布时间

2022.8.2

操作系统

Linux 64-bit

CUDA Toolkit

11.7

备注

底层物理主机仅需要参考本文安装NVIDIA Linux驱动,实际运行业务的虚拟机或容器才需要 安装NVIDIA CUDA

本文在 私有云架构 的底层物理主机安装GPU的Linux驱动

通过Linux发行版软件仓库方式安装NVDIA CUDA驱动

备注

建议采用发行版软件仓库方式安装,方便后续维护升级

详情请参考 NVIDIA Driver Installation Quickstart Guide

注意详细检查兼容版本细节,以官方文档为准,避免踩坑。例如,我现在部署在 Fedora 虚拟机中,选择官方文档明确指出的 41 版本(虽然最新版本42也可能支持)

安装NVIDIA Linux驱动的方法实际上和 安装NVIDIA CUDA 完全一样,除了最后的安装命令差异:

Ubuntu软件仓库方式安装NVDIA CUDA驱动

我的 私有云架构 采用了 Ubuntu 22.04 LTS

  • 执行Ubuntu添加仓库:

在Ubuntu 22.04操作系统添加NVIDIA官方软件仓库配置
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb
sudo dpkg -i cuda-keyring_1.0-1_all.deb
sudo apt-get update
  • 安装 NVIDIA CUDA 驱动:

Debian/Ubuntu使用NVIDIA官方软件仓库安装CUDA驱动
sudo apt-get -y install cuda-drivers

安装过程会爱用 动态内核模块支持(DKMS) 编译NVIDIA内核模块,并且会提示添加了 /etc/modprobe.d/nvidia-graphics-drivers.confblacklist 阻止加载冲突的 Nouveau 开源驱动,并且提示需要重启操作系统来完成驱动验证加载。

RHEL/CentOS 7 软件仓库方式安装NVDIA CUDA驱动

CentOS 7安装NVIDIA驱动步骤:

  • 执行RHEL/CentOS 7仓库添加:

在RHEL/CentOS 7操作系统添加NVIDIA官方软件仓库配置
# CentOS7可能需要安装编译工具链, RHEL7通常已经安装
sudo dnf install -y tar bzip2 make automake gcc gcc-c++ pciutils elfutils-libelf-devel libglvnd-devel iptables firewalld vim bind-utils wget

# 安装EPEL仓库
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

# 对于RHEL7还需要激活一些可选仓库(CentOS7无需此操作)
sudo subscription-manager repos --enable="rhel-*-optional-rpms" --enable="rhel-*-extras-rpms"  --enable="rhel-ha-for-rhel-*-server-rpms"

# 安装CUDA仓库公钥
distribution=$(. /etc/os-release;echo $ID`rpm -E "%{?rhel}%{?fedora}"`)

# 设置仓库
ARCH=$( /bin/arch )
sudo yum-config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/$distribution/${ARCH}/cuda-$distribution.repo

# 安装Kernel头文件
sudo yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r)

# 清理缓存
sudo yum clean expire-cache
  • 安装 NVIDIA CUDA 驱动:

RHEL/CentOS 7使用NVIDIA官方软件仓库安装CUDA驱动
sudo yum -y install cuda-drivers

Fedora 41 软件仓库方式安装NVIDIA CUDA驱动

Fedora 41 (通过 bhyve(BSD hypervisor) 虚拟机):

CUDA驱动安装后操作

CUDA驱动安装完成后,需要按照 安装NVIDIA CUDA安装CUDA完成后操作 步骤,一样做一遍环境变量设置、NVIDIA持久化daemon以及验证驱动是否正确安装。不过,我检查文档发现似乎在CUDA驱动安装上没有太大关系,暂时忽略。

  • 重启操作系统,检查驱动安装:

    nvidia-smi
    

输出显示:

安装完NVIDIA驱动后,检查 nvidia-smi 输出
Sun Oct 30 22:23:29 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 520.61.05    Driver Version: 520.61.05    CUDA Version: 11.8     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA Graphics...  On   | 00000000:82:00.0 Off |                    0 |
| N/A   30C    P8     9W / 150W |      0MiB / 23040MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

警告

我在安装NVIDIA CUDA驱动时搞了一个乌龙,我忘记之前在 Open Virtual Machine Firmware(OMVF) 配置了GPU的内核隔离 vfio-pci.ids=...,10de:1b39 导致NVIDIA设备被passthrough给虚拟机 z-iommu 。所以物理主机加载 nvidia-nvlink 就出现冲突错误。详见下文 异常排查

异常排查

我安装完 NVIDIA CUDA drivers 之后重启系统,发现控制台不断打印错误(大约每秒重复1~2次):

NVRM:  The NVIDIA probe routine was not called for 1 device(s)
...

并且按照CUDA安装检查 cat /proc/driver/nvidia/version 也没有看到该文件,说明驱动没有正常安装

参考 PSA. If you run kernel 5.18 with NVIDIA, pass 'ibt=off' to your kernel cmd line if your NVIDIA driver refuses to load. 。但是这个方法似乎无效(IBT是Intel的控制流完整性保护control flow integrity protection),按照 arch linux: NVIDIA 确实提到在内核5.18或更高,需要配置 ibt=off

我检查了 dmesg -T 输出发现:

[Sat Oct 29 20:58:55 2022] nvidia-nvlink: Nvlink Core is being initialized, major device number 508
[Sat Oct 29 20:58:55 2022] NVRM: The NVIDIA probe routine was not called for 1 device(s).
[Sat Oct 29 20:58:55 2022] NVRM: This can occur when a driver such as:
                           NVRM: nouveau, rivafb, nvidiafb or rivatv
                           NVRM: was loaded and obtained ownership of the NVIDIA device(s).
[Sat Oct 29 20:58:55 2022] NVRM: Try unloading the conflicting kernel module (and/or
                           NVRM: reconfigure your kernel without the conflicting
                           NVRM: driver(s)), then try loading the NVIDIA kernel module
                           NVRM: again.
[Sat Oct 29 20:58:55 2022] NVRM: No NVIDIA devices probed.
[Sat Oct 29 20:58:55 2022] nvidia-nvlink: Unregistered Nvlink Core, major device number 508

这说明系统加载了和NVIDIA驱动冲突的内核模块,例如 nouveau, rivafb, nvidiafb or rivatv

不过,比较奇怪,我使用 lsmod 是看不到上述4个驱动模块的,有可能是编译在内核中了?

检查当前内核加载模块:

lsmod | grep nv

看起来加载了不少 nvidia 相关内核模块:

nvidia              55201792  1
nvme_fabrics           24576  0
nvme                   49152  0
drm                   622592  4 drm_kms_helper,nvidia,mgag200
nvme_core             135168  2 nvme,nvme_fabrics

我怀疑是没有按照前文提示添加 /etc/modprobe.d/nvidia-graphics-drivers.conf 导致启动时不断自动加载开源,所以产生了冲突?

通过 mlocate 软件包的 updatedb + locate nvidia-graphics-drivers.conf 找到位于 /usr/lib/modprobe.d/nvidia-graphics-drivers.conf 复制到 /etc/modprobe.d/ 目录:

cp /usr/lib/modprobe.d/nvidia-graphics-drivers.conf /etc/modprobe.d/

这个 nvidia-graphics-drivers.conf 内容如下:

/etc/modprobe.d/nvidia-graphics-drivers.conf
blacklist nouveau
blacklist lbm-nouveau
blacklist nvidiafb
alias nouveau off
alias lbm-nouveau off

汗,虽然理论上配置正确,但是还是没有解决上述报错

仔细观察发现,有两个 modprobe 进程一直卡住 ps aux | grep modprobe 可以看到:

root        4619 98.0  0.0  72868  2320 ?        D    22:20   0:00 modprobe nvidia
root        4622  0.0  0.0  72868  2416 ?        R    22:20   0:00 /sbin/modprobe nvidia-drm

并且进程号不断变化,显示不断在重复执行

当前 lspci | grep -i nvidia 看到硬件输出:

82:00.0 3D controller: NVIDIA Corporation GP102GL [Tesla P10] (rev a1)

参考 How to check if the NVIDIA drivers/modules are installed? ,对于正常安装的 NVIDIA 驱动,执行 nvidia-smi 需要看到驱动信息

  • 检查启动日志:

    journalctl --grep="nvidia"
    

我发现在加载最初还有一行日志报错,之前没有注意:

-- Boot dec22114bd1f42a9b8128b527ddee1c9 --
Oct 29 12:35:19 zcloud kernel: nvidia: loading out-of-tree module taints kernel.
Oct 29 12:35:19 zcloud kernel: nvidia: module license 'NVIDIA' taints kernel.
Oct 29 12:35:19 zcloud kernel: nvidia: module verification failed: signature and/or required key missing - tainting kernel
Oct 29 12:35:19 zcloud kernel: nvidia-nvlink: Nvlink Core is being initialized, major device number 510
Oct 29 12:35:19 zcloud kernel: NVRM: The NVIDIA probe routine was not called for 1 device(s).
Oct 29 12:35:19 zcloud kernel: NVRM: This can occur when a driver such as:
                               NVRM: nouveau, rivafb, nvidiafb or rivatv
                               NVRM: was loaded and obtained ownership of the NVIDIA device(s).
Oct 29 12:35:19 zcloud kernel: NVRM: Try unloading the conflicting kernel module (and/or
                               NVRM: reconfigure your kernel without the conflicting
                               NVRM: driver(s)), then try loading the NVIDIA kernel module
                               NVRM: again.
Oct 29 12:35:19 zcloud kernel: NVRM: No NVIDIA devices probed.
Oct 29 12:35:19 zcloud kernel: nvidia-nvlink: Unregistered Nvlink Core, major device number 510

不过出现 nvidia: module verification failed: signature and/or required key missing - tainting kernel 并不影响,只是表示NVIDIA并没有签名驱动,Linux内核会检查内核模块签名,即使 secure boot 被禁用。使用 journalctl --grep="secure" 可以看到内核启动确实禁用了Secure boot:

Sep 27 11:43:19 zcloud kernel: secureboot: Secure boot disabled

参考 Nvidia issue (讨论驱动加载), 在添加了 noveau 模块屏蔽之后,还要更新 initramfs

update-initramfs -u -k $(uname -r)

但是,我甚至还添加了:

blacklist rivafb
blacklist nvidiafb
blacklist rivatv

但是依然没有解决

参考 The NVIDIA probe routine was not called for 1 device(s) #1 在内核参数添加 rdblaclist=nouveau ,然后执行 update-grub 。可惜,还是不行

  • 执行 lspci -vvv 可以看到显卡设备:

    82:00.0 3D controller: NVIDIA Corporation GP102GL [Tesla P10] (rev a1)
         Subsystem: NVIDIA Corporation GP102GL [Tesla P10]
         Physical Slot: 3
    ...
         Kernel driver in use: vfio-pci
         Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia
    

为何还是加载了 nvidiafbnouveau ?

在华为的FusionServer Pro Server GPU Card Operation Guide 05 How to Disable the Nouveau Driver for Different Linux Systems 说明了不同操作系统屏蔽nouveu驱动方法,其中 Ubuntu 采用:

blacklist nouveau
options nouveau modeset=0

这个方法和 How to disable Nouveau kernel driver 一致,所以我修订 /etc/modprobe.d/nvidia-graphics-drivers.conf 增加一行 options nouveau modeset=0

blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off

但是重启后使用 lspci -vvv 看到依然在NVIDIA段落:

...
     Kernel driver in use: vfio-pci
     Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia

奔溃...

我改为手工删除掉内核模块:

mkdir ~/`uname -r`
mv /usr/lib/modules/`uname -r`/kernel/drivers/video/fbdev/nvidia/nvidiafb.ko ~/`uname -r`/
mv /usr/lib/modules/`uname -r`/kernel/drivers/gpu/drm/nouveau/nouveau.ko ~/`uname -r`/
mv /usr/lib/modules/`uname -r`/kernel/drivers/video/fbdev/riva/rivafb.ko ~/`uname -r`/
# 没有找到 rivatv.ko

再次奔溃...重启后报错依旧(执行过 update-initramfs -u 之后也一样)

我还尝试在 /etc/default/grub 中为内核参数添加了 rd.driver.blacklist=nouveau,rivafb,nvidiafb,rivatv ,但是启动之后依然出现上述报错

严重失误

我逐渐感觉并不是内核加载了和nvidia模块冲突的nouveau等模块 而是可能是因为内核启用了 IOMMU 导致的: 我翻了一下我之前的笔记,确实在 Open Virtual Machine Firmware(OMVF) 实践时,将 GPU 卡直接passthrough给了虚拟机 z-iommu 做测试。

仔细看了 Open Virtual Machine Firmware(OMVF) 记录,在 通过设备ID来绑定 vfio-pci 配置了将GPU设备 10de:1b39 屏蔽了(提供给kvm虚拟机passthrough),所以就会出现上述的报错。真是非常乌龙...

  • 所以修订方法也很简单,就是去除掉 /etc/default/grubvfio-pci.ids=144d:a80a,10de:1b39 改为 vfio-pci.ids=144d:a80a 就不会隔离掉GPU,物理主机就可以使用该设备

参考