收起左侧

1.1.30 vGPU驱动加载失败且编译失败问题解决

0
回复
35
查看
[ 复制链接 ]

飞牛升级1.1.30将Linux内核也升级到了6.18.18-trim 之前通过DKMS一键编译驱动的方法已经失效了,因为新内核在老驱动可以说是完全不兼容,本教程将通过修改驱动C代码实现兼容,建议在AI辅助下进行操作!!如果能升级vGPU驱动建议优先选择升级,本教程不适合纯小白!!!

飞牛升级内核导致vgpu驱动加载错误解决方案 - 攻略分享 飞牛私有云论坛 fnOS

本文以 nvidia/535.230.026.18.18-trim 内核为例。实际操作时要注意修改为自己的驱动版本号

1. 先理解问题

NVIDIA 驱动不是普通应用,它需要编译出和当前内核匹配的内核模块,例如:

  • nvidia.ko
  • nvidia-uvm.ko
  • nvidia-modeset.ko
  • nvidia-drm.ko
  • nvidia-peermem.ko

内核升级后,旧驱动源码可能跟不上新内核接口变化,于是 DKMS 自动编译失败。常见表现是:

dkms build nvidia/535.230.02

输出类似:

Error! Bad return status for module build on kernel: 6.18.18-trim (x86_64)
Consult /var/lib/dkms/nvidia/535.230.02/build/make.log for more information.

这句话只表示“编译失败”,真正原因在 make.log 里。

2. 排查前准备

先切换到管理员权限。飞牛 NAS 默认不一定允许直接使用 root 登录,建议通过已有管理员账号使用 sudo

sudo -i

确认当前内核:

kernel="$(uname -r)"
echo "$kernel"

查看 DKMS 状态:

dkms status

查看最近一次 NVIDIA DKMS 构建日志:

tail -n 160 /var/lib/dkms/nvidia/535.230.02/build/make.log

3. 第一类错误:找不到 NVIDIA 公共头文件

如果日志中出现:

fatal error: os-interface.h: No such file or directory
fatal error: nv-firmware.h: No such file or directory
fatal error: nv-dmabuf.h: No such file or directory
fatal error: nv-pci-types.h: No such file or directory

说明 NVIDIA 源码不是完全缺失,而是编译参数没有正确带上 common/inc include 路径。

先确认头文件确实存在:

find /usr/src/nvidia-535.230.02 -name os-interface.h -o -name nv-firmware.h

如果能看到类似:

/usr/src/nvidia-535.230.02/common/inc/os-interface.h
/usr/src/nvidia-535.230.02/common/inc/nv-firmware.h

就说明源码在,只是新内核 Kbuild 没有吃到旧驱动写在 EXTRA_CFLAGS 里的参数。

备份并修复:

src="/usr/src/nvidia-535.230.02/Kbuild"
cp -a "$src" "$src.bak-$(date +%Y%m%d-%H%M%S)"

if ! grep -q 'ccflags-y += $(EXTRA_CFLAGS)' "$src"; then
    printf '\nccflags-y += $(EXTRA_CFLAGS)\n' >> "$src"
fi

4. 第二类错误:timer 接口变更

如果日志中出现:

error: implicit declaration of function 'del_timer_sync'

说明当前内核已经使用新接口 timer_delete_sync()

确认内核头文件:

grep -n "timer_delete_sync" "/lib/modules/$(uname -r)/build/include/linux/timer.h"

如果存在,就给 NVIDIA Kbuild 添加兼容宏:

src="/usr/src/nvidia-535.230.02/Kbuild"
cp -a "$src" "$src.timer-bak-$(date +%Y%m%d-%H%M%S)"

if ! grep -q "del_timer_sync=timer_delete_sync" "$src"; then
    cat >> "$src" <<'EOF'
ifneq ($(shell grep -q "timer_delete_sync" "$(NV_KERNEL_SOURCES)/include/linux/timer.h" 2>/dev/null && echo y),)
ccflags-y += -Ddel_timer_sync=timer_delete_sync
endif
EOF
fi

5. 第三类错误:DRM 接口变更

如果日志中出现这些错误:

fb_create from incompatible pointer type
struct drm_driver has no member named 'date'
mode_valid from incompatible pointer type

说明 DRM 子系统接口发生了变化:

  • fb_create 多了 const struct drm_format_info *info 参数
  • connector mode_valid 的 mode 参数变成了 const
  • struct drm_driver.date 字段被移除

这一步需要改 NVIDIA DRM 源码。建议只做条件兼容,不要把逻辑写死到某一个内核版本。

需要修改的文件通常是:

/usr/src/nvidia-535.230.02/Kbuild
/usr/src/nvidia-535.230.02/nvidia-drm/nvidia-drm-drv.c
/usr/src/nvidia-535.230.02/nvidia-drm/nvidia-drm-connector.c
/usr/src/nvidia-535.230.02/nvidia-drm/nvidia-drm-fb.c
/usr/src/nvidia-535.230.02/nvidia-drm/nvidia-drm-fb.h

建议每改一个文件都先备份:

file="/usr/src/nvidia-535.230.02/nvidia-drm/nvidia-drm-drv.c"
cp -a "$file" "$file.bak-$(date +%Y%m%d-%H%M%S)"

核心思路是:

  • Kbuild 中检测内核头文件是否包含新接口
  • 根据检测结果定义宏
  • 在 C 文件里用 #if defined(...) 同时兼容新旧内核

示例宏:

ifneq ($(shell grep -q "const struct drm_format_info \*info" "$(NV_KERNEL_SOURCES)/include/drm/drm_mode_config.h" 2>/dev/null && echo y),)
ccflags-y += -DNV_DRM_MODE_CONFIG_FUNCS_FB_CREATE_HAS_FORMAT_INFO_ARG
endif

ifneq ($(shell grep -q "const struct drm_display_mode \*mode" "$(NV_KERNEL_SOURCES)/include/drm/drm_modeset_helper_vtables.h" 2>/dev/null && echo y),)
ccflags-y += -DNV_DRM_CONNECTOR_MODE_VALID_HAS_CONST_MODE_ARG
endif

ifneq ($(shell grep -q "[[:space:]]date;" "$(NV_KERNEL_SOURCES)/include/drm/drm_drv.h" 2>/dev/null && echo y),)
ccflags-y += -DNV_DRM_DRIVER_HAS_DATE
endif

6. 第四类错误:GPL-only 符号

如果编译已经进入 MODPOST 阶段,但失败为:

ERROR: modpost: GPL-incompatible module nvidia.ko uses GPL-only symbol '__vma_start_write'

这说明 NVIDIA 535 调用了 vm_flags_set() / vm_flags_clear(),而新内核里这两个内联函数会间接引用 GPL-only 符号。闭源 NVIDIA 模块不能引用这个符号。

可以改 NVIDIA 自己的包装函数,让它优先使用 __vm_flags_mod()

目标文件:

/usr/src/nvidia-535.230.02/common/inc/nv-mm.h

核心思路:

#if defined(NV___VM_FLAGS_MOD_PRESENT)
    __vm_flags_mod(vma, flags, 0);
#else
    vm_flags_set(vma, flags);
#endif

对应清理 flags 时:

#if defined(NV___VM_FLAGS_MOD_PRESENT)
    __vm_flags_mod(vma, 0, flags);
#else
    vm_flags_clear(vma, flags);
#endif

同时在 Kbuild 中检测:

ifneq ($(shell grep -q "static inline void __vm_flags_mod" "$(NV_KERNEL_SOURCES)/include/linux/mm.h" 2>/dev/null && echo y),)
ccflags-y += -DNV___VM_FLAGS_MOD_PRESENT
endif

7. 重新构建和安装 DKMS

构建:

dkms build nvidia/535.230.02

安装:

dkms install nvidia/535.230.02

查看状态:

dkms status

正常应看到:

nvidia/535.230.02, 6.18.18-trim, x86_64: installed

8. 注意模块版本冲突

飞牛系统可能自带另一套 NVIDIA 模块,例如 580.142。如果你的 GPU 只支持 535,而系统优先加载 580,就会出现:

NVRM: The NVIDIA GPU ... is not supported by the NVIDIA 580.142 driver release.
modprobe: ERROR: could not insert 'nvidia': No such device

确认当前 modprobe 会加载哪个模块:

modprobe --show-depends -S "$(uname -r)" nvidia | head -n 5

如果它指向:

/lib/modules/.../updates/trim/alternatives/nvidia-gpu/nvidia.ko

而不是:

/lib/modules/.../updates/dkms/nvidia.ko

可以添加 depmod 覆盖规则,让 DKMS 的 535 优先:

cat > /etc/depmod.d/nvidia-dkms-535.conf <<'EOF'
override nvidia * updates/dkms
override nvidia-uvm * updates/dkms
override nvidia-modeset * updates/dkms
override nvidia-drm * updates/dkms
override nvidia-peermem * updates/dkms
EOF

depmod -a "$(uname -r)"

再次确认:

modprobe --show-depends -S "$(uname -r)" nvidia | head -n 5

应该指向:

/lib/modules/当前内核/updates/dkms/nvidia.ko

9. 加载和验证

加载模块:

modprobe nvidia
modprobe nvidia-uvm
modprobe nvidia-modeset
modprobe nvidia-drm

查看模块是否加载:

lsmod | grep -E '^nvidia'

查看 GPU:

nvidia-smi

如果成功,会看到类似:

NVIDIA-SMI 535.230.02
Driver Version: 535.230.02
GPU  Name
GRID P4-2Q

也可以用更适合脚本检查的方式:

nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader

10. 新手排障顺序总结

遇到 DKMS 失败时,不要先猜原因,按这个顺序查:

  1. 看当前内核:

    uname -r
    
  2. 看 DKMS 状态:

    dkms status
    
  3. 看真正错误日志:

    tail -n 160 /var/lib/dkms/nvidia/535.230.02/build/make.log
    
  4. 每次只修复一个明确错误。

  5. 每次改源码前都备份。

  6. 构建成功后再安装。

  7. 安装后确认 modprobe 实际加载的是正确版本。

  8. 最后用 nvidia-smi 验证。

11. 本次处理结果参考

本次实际处理后的关键结果:

DKMS 状态:
nvidia/535.230.02, 6.18.18-trim, x86_64: installed

模块路径:
/lib/modules/6.18.18-trim/updates/dkms/nvidia.ko

GPU 查询:
GRID P4-2Q, 535.230.02, 2048 MiB

这说明:

  • NVIDIA 535 DKMS 已经适配当前内核并安装成功
  • 系统模块解析顺序已经切到 DKMS 版本
  • 驱动能正常加载
  • nvidia-smi 能正常识别 GPU

12. 回滚建议

如果后续需要回滚,优先按备份文件恢复,而不是直接删除目录。

查看备份:

find /usr/src/nvidia-535.230.02 -name "*.bak-*" -o -name "*.sig-bak-*" -o -name "*.vmflags*-bak-*"

移除 depmod 覆盖规则:

rm -f /etc/depmod.d/nvidia-dkms-535.conf
depmod -a "$(uname -r)"

卸载 DKMS 模块:

dkms remove nvidia/535.230.02 --all

回滚前建议先确认业务是否依赖 GPU,避免影响正在运行的转码、虚拟化或容器任务。

收藏
送赞 1
分享
https://www.xiaozhuhouses.asia/欢迎访问我的博客
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则