在FreeBSD Linux Jail中运行NVIDIA Cuda

我一直在想如何能够实现一个 FreeBSD机器学习 环境,结合FreeBSD强大的 ZFS 以及坚如磐石的基础,实现通常在Linux环境下的Machine Learning。

我最初想到的是 bhyve PCI Passthrough ,毕竟这是非常直觉的想法,通过PCIe Passthrough实现GPU直通给Linux虚拟机,这样就避免了 NVIDIA GPU 无法很好在FreeBSD支持的问题(我相像中厂商对FreeBSD硬件驱动支持都比较弱)。不过,现实总是比较残酷,在反复折腾 在bhyve中实现NVIDIA GPU passthrough 遇到各种问题,让人非常沮丧: 花费了大量的时间精力,这些时间本应该投入到现今火热一日千里的 LLM 大型语言模型 实践中。

linux jail思路

Davinci Resolve installed in Freebsd Jail 提供了一个新的思路:

  • 在FreeBSD上安装 nvidia-driver linux-nvidia-libs libc6-shim libvdpau-va-gl libva-nvidia-driver (实际上和下文 linuxulator思路 是一致的)

  • 配置 FreeBSD Linux Jail 在Jail中运行 Ubuntu Linux

  • 在Ubuntu Linux Jail中运行安装 nvidia-driver (这里思路有点乱,我不太确定Linux Jail中是否还要安装driver,因为FreeBSD Host上已经安装过driver了) 和 nvidia-cuda-toolkit

  • 接下来就可以安装任意依赖NVIDIA CUDA的应用

备注

另一种解决思路是 在 FreeBSD Linuxulator 中运行NVIDIA Cuda ,更为简便

警告

目前我的实践还遇到一些困难没有解决,待后续再尝试:

Host安装 Linuxulator 软件栈

NVIDIA为FreeBSD提供了原生的 nvidia-driver 驱动,所以方案类似 Docker运行NVIDIA容器 ,首先在FreeBSD Host中安装 nvidia-driver 以及支持 Linuxulator 运行模拟Linux驱动的 linux-nvidia-libs 库文件(我理解是将Linux层调用Linux版本 nvidia-driver 的API转换成调用FreeBSD版本 nvidia-driver )。此外,附加安装 libc6-shim 能够获得一个 nv-sglrun 工具来包装使用CUDA:

在FreeBSD上安装 nvidia-driver (原生) 和 CUDA (Linux版)
pkg install nvidia-driver linux-nvidia-libs libc6-shim

备注

DaVinci Resolve Freebsd 中另外安装的两个库文件:

  • libvdpau-va-gl : Linux二进制程序,提供应用程序使用VDPAU(Video Decode and Presentation API)来实现硬件功能,将 VDPAU 调用转换成视屏加速API(VA-API, Video Acceleration API),使用OpenGL来绘制和伸缩。这个库对于Intel GPU也有部分作用,因为Intel GPU没有实现原生VDPAU但支持VA-API

  • libva-nvidia-driver : Linux平台的NVIDIA GPU作为转换层提供硬件视频解码的软件包,桥接了 VA-API (Video Acceleration API),被很多应用程序用于(NVIDIA)硬件解码。

上述两个库似乎是视频相关,我暂时没有安装

  • 重启系统后执行 nvidia-smi 发现报错:

执行 nvidia-smi 显示没有驱动
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
  • 手工加载 NVIDIA 驱动:

手工加载nvidia驱动
kldload nvidia

此时检查 kldstat | grep nvidia 看到有一个内核模块加载:

检查 kldstat 输出中有 nvidia
kldstat | grep nvidia

另外,还需要配置系统启动时自动加载 nvidia-devier ,设置 /boot/loader.conf :

设置 /boot/loader.conf
# NVIDIA
nvidia_load="YES"

警告

我遇到一个非常奇怪的问题,在 /boot/loader.conf 添加了 nvidia_load="YES" ,但是重启没有自动加载 nvidia 驱动,而是启动后每次都需要手工执行 kldload nvidia 加载。这让我很困惑,参考 Loading kernel modules automatically 似乎是配置文件有隐含特殊字符导致的,但是我没有找到解决方法。

输出显示:

检查 kldstat 输出中有 nvidia
22    1 0xffffffff83800000  604e158 nvidia.ko

但是很不幸,发现 nvidia-smi 报错依旧:

执行 nvidia-smi 显示没有驱动
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
  • 检查系统日志 dmesg 显示:

dmesg 显示分配BAR错误
nvidia0: <Unknown> on vgapci0
vgapci0: child nvidia0 requested pci_enable_io
vgapci0: 0x800000000 bytes of rid 0x14 res 3 failed (0, 0xffffffffffffffff).
nvidia0: NVRM: NVIDIA MEM resource alloc failed, BAR1 @ 0x14.
nvidia0: NVRM: NVIDIA hardware alloc failed.
device_attach: nvidia0 attach returned 6

这说明系统没有设置 Above 4G Decoding BIOS设置 或者说类似 HP DL360 Gen9 Large Bar Memory(Tesla P10) (相同概念的不同术语),需要调整BIOS

BIOS设置 Above 4G Decoding BIOS设置

Above 4G Decoding BIOS设置 针对我的 纳斯NASSE C246 ITX主板 需要配置2个BIOS位置:

  • Above 4G Decoding

../../../_images/above_4gb_decoding.png
  • above 4GB mmio BIOS Assignment

../../../_images/above_4gb_mmio_bios_assignment.png

完成后重启主机,然后在FreeBSD Host主机上执行 nvidia-smi 此时就看到正常的输出信息(表明 Nvidia Tesla P10 GPU运算卡 已经工作正常:

nvidia-smi 输出显示GPU工作正常
Fri Sep 26 19:51:25 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.07              Driver Version: 580.82.07      CUDA Version: N/A      |
+-----------------------------------------+------------------------+----------------------+
| 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 Device         Off |   00000000:01:00.0 Off |                    0 |
| N/A   32C    P0             36W /  150W |       0MiB /  23040MiB |      2%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

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

注意,这里输出信息中仅显示 Driver Version: 580.82.07 ,而CUDA版本是空白的 CUDA Version: N/A 。这时因为当前使用的 nvidia-smi 仅仅是FreeBSD原生的 nvidia-driver

  • 通过 nv-sglrun 运行 nvidia-smi 则是执行Linux程序(通过 Linuxulator ),会通过CUDA,此时会看到CUDA版本信息:

通过 nv-sglrun 运行 nvidia-smi
nv-sglrun nvidia-smi

输出信息:

通过 nv-sglrun 运行 nvidia-smi 输出信息中有CUDA版本信息
/usr/local/lib/libc6-shim/libc6.so: shim init
/usr/local/lib/libc6-shim/libc6.so: unable to load libinotify.so.0 (Shared object "libinotify.so.0" not found, required by "nvidia-smi")
Fri Sep 26 19:53:59 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.07              Driver Version: 580.82.07      CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| 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 Device         Off |   00000000:01:00.0 Off |                    0 |
| N/A   33C    P0             36W /  150W |       0MiB /  23040MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

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

至此,FreeBSD nvidia-driver 以及通过 Linuxulator 运行 CUDA 已部署完毕,接下来就可以进行 Machine Learning 工作。当然,为了进一步方便工作,还可以继续部署 FreeBSD Linux Jail 来实现隔离且完整的机器学习环境

  • 如果要直接在FreeBSD Linuxulator 环境运行Linux版本Conda,可以安装 miniconda Linux版本:

安装Linux版本miniconda
pkg install linux-miniconda-installer
miniconda-installer

此时会安装一个Linux版本的 miniconda,可以用于今后机器学习安装对应的软件包

Linux Jail实现CUDA实践

备注

由于上文已经在FreeBSD Host中安装了 nvidia-driver ,所以参考 Docker运行NVIDIA容器 架构,在Jail中,应该只需要安装Linux版本的 CUDA Toolkit,而不需要安装完整版本的CUDA(包含 cuda-toolkitnvidia-driver )

Debian/Ubuntu使用NVIDIA官方软件仓库安装CUDA驱动
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
  • 安装 nvidia-cuda-toolkit :

安装 nvidia-cuda-toolkit
apt-get install cuda-toolkit

备注

我发现NVIDIA提供了不同的CUDA Toolkit: 仓库中有

  • nvidia-cuda-toolkit

  • cuda-toolkit

两者在 Ubuntu Linux core系统中安装:

  • nvidia-cuda-toolkit 需要 6037 MB 空间

  • cuda-toolkit 需要 7474 MB 空间

  • 两者安装的软件包和依赖有所不同

以下这段内容来自Google AI:

  • nvidia-cuda-toolkit 是完整版本的CUDA Toolkit,也称为 full development suite 。包含了完整CUDA开发工具和库,适合需要完整toolchain来编译、调试和prifile CUDA程序的开发者。当安装完整版本 nvidia-cuda-toolkit 通常会处理依赖以及安装NVIDIA驱动

  • ( 这段似乎不正确 Google AI似乎搞混了Conda环境中的 cudatoolkit 包) cuda-toolkit 通常用于Conda包或者较为核心的toolkit,软件包较少仅包含运行软件(如 Tensorflow )所需的库,没有包含完整的开发toolchain。这个软件包组合通常是最终用户使用的,仅用于预编译应用程序或Python软件包,如 PytorchTensorflow 。安装 cuda-toolkit 通常假设系统已经安装了NVIDIA GPU驱动,所以安装软件更少。

  • 如果需要完整开发环境来编写C++ CUDA程序,则安装完整版本 nvidia-cuda-toolkit ; 如果只是最终用户运行预编译程序,例如安装运行 深度学习 框架如 PytorchTensorflow ,则通常安装轻量级 cuda-toolkit (通过 condapip 安装 cudatoolkit 软件包)

这里有一些报错,看来是安装 nvidia-cuda-toolkit 时自动安装和配置 Systemd进程管理器 导致的:

安装 nvidia-cuda-toolkit 报错
Setting up libsystemd-shared:amd64 (255.4-1ubuntu8.10) ...
Setting up systemd-dev (255.4-1ubuntu8.10) ...
Setting up systemd (255.4-1ubuntu8.10) ...
⚠️  /proc/ is not mounted. This is not a supported mode of operation. Please fix
your invocation environment to mount /proc/ and /sys/ properly. Proceeding anyway.
Your mileage may vary.
⚠️  /proc/ is not mounted. This is not a supported mode of operation. Please fix
your invocation environment to mount /proc/ and /sys/ properly. Proceeding anyway.
Your mileage may vary.
⚠️  /proc/ is not mounted. This is not a supported mode of operation. Please fix
your invocation environment to mount /proc/ and /sys/ properly. Proceeding anyway.
Your mileage may vary.
/proc/ is not mounted, but required for successful operation of systemd-tmpfiles. Please mount /proc/. Alternatively, consider using the --root= or --image= switches.
Failed to take /etc/passwd lock: Invalid argument
dpkg: error processing package systemd (--configure):
 installed systemd package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
 systemd
E: Sub-process /usr/bin/dpkg returned an error code (1)

备注

我曾经想是不是应该改为安装 NVIDIA Container Toolkit ?面向容器定制的toolkit或许可以避免 systemd 问题...

我参考 NVIDIA Container Toolkit 发现也不行,这个 NVIDIA Container Toolkit 是一个复杂的安装在Host上的软件包,用于配置 Docker 或其他 Container 运行时来实现容器化运行 CUDA Toolkit

也就是说,确实应该在容器(或者Jail)内部安装 CUDA Toolkit ,但是没法使用NVIDIA官方的 NVIDIA Container Toolkit ,这个软件包和Linux平台深度绑定,只是为了能够方便构建和运行容器,但无法在FreeBSD上使用。

这个问题似乎不好解决,但也可能可以解决(google ai给了启发):

  • Devuan 是一个 Debian fork版本,采用了 sysvinit 系统替代 Systemd进程管理器 ,理论上当安装 nvidia-cuda-toolkit 的依赖时或许可以避免 systemd 问题(不过也取决于NVIDIA开发的软件包是否强制依赖了 systemd )

  • 使用CUDA runfile installer安装,有可能通过 --override 参数bypass掉依赖检查,不过CUDA系统可能会依赖才能工作

参考