ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ubuntu内核升级后NVIDIA驱动失效?一文教你快速恢复与预防

Ubuntu内核升级后NVIDIA驱动失效?一文教你快速恢复与预防 如果你的 Ubuntu 突然在升级完内核之后进不去图形界面或者登录后只剩一个终端又或者是 NVIDIA 驱动明明装了但nvidia-smi直接报错先别急着重装系统。这个标题里的场景我太熟悉了——Ubuntu 系统内核Kernel升级与 NVIDIA 预编译内核模块的版本脱节几乎是每个用 NVIDIA 显卡跑 Ubuntu 的人都会踩进去的坑而且一踩就是大半天起步。先说这个问题的本质NVIDIA 驱动不是纯用户态软件它的核心是一个内核模块这个模块必须针对你当前运行的内核版本单独编译或者使用 NVIDIA 官方为某个内核版本预编译好的二进制版本。Ubuntu 的自动更新挺勤快内核从 5.15 升到 6.5 也就一个命令的事但 NVIDIA 驱动不会自动跟着你的新内核重新编译。于是系统重启之后内核找到了新的内核模块列表发现里面没有 nvidia.ko或者模块签名对不上结果就是显卡驱动加载失败显示服务起不来桌面进不去。这篇文章我来完整拆解这个场景的来龙去脉把排查思路、恢复步骤、以及以后怎么避免再踩坑都写清楚适合所有在 Ubuntu包括 22.04、24.04 及衍生版本上使用 NVIDIA 显卡的朋友无论是刚入门的新手还是经验丰富的老手都能从里面找到能直接用的操作。1. 问题全景为什么内核一升级NVIDIA 显卡就“猝死”1.1 先理解 Ubuntu 下的 NVIDIA 驱动到底是怎么组成的很多人以为 NVIDIA 驱动就是那个几百 MB 的.run安装包装完之后就万事大吉。实际上你装进系统的是一个组合体里面有用户态库libcuda、libnvidia-glcore 这类、显卡控制面板nvidia-settings、调试工具nvidia-smi也就是能看显存占用和驱动版本的那个命令行工具还有最核心的内核模块 nvidia.ko、nvidia-modeset.ko、nvidia-drm.ko 这几个文件。这些.ko文件会被安装到/lib/modules/$(uname -r)/updates/dkms/目录下如果用 DKMS 方式装或者/lib/modules/$(uname -r)/kernel/drivers/video/nvidia/目录下如果用 runfile 方式装。注意看这个路径里面带了$(uname -r)也就是说内核模块是为特定内核版本编译的。当你升级内核后新内核对应的模块目录/lib/modules/6.5.0-x-generic/是一个全新目录老驱动编译出来的nvidia.ko还在旧内核目录里新内核目录要么空着要么只有系统通用模块。内核启动时按depmod生成的依赖关系去加载nvidia模块找不到于是加载失败GPU 驱动整体失效。1.2 预编译模块和 DKMS 编译模块的区别这里有个关键概念标题里提到了“预编译内核模块”。NVIDIA 官方在发布驱动程序时除了提供开源驱动源代码nvidia-open还会针对部分 Linux 发行版提供预编译好的二进制模块官方称之为 precompiled kernel modules 或者 NVIDIA updates即通过 NVIDIA 官方 apt 仓库提供的所谓“短期支持分支”的驱动。预编译模块的好处是安装速度快、不依赖编译工具链、不需要装 gcc 和 linux-headers。坏处就是它只针对特定的内核版本编译NVIDIA 会在驱动发布时锁死支持的内核版本范围。举个例子NVIDIA 535 版本驱动发布时可能只支持到 6.2 内核如果你把内核升到 6.8预编译模块立马失效。而 DKMSDynamic Kernel Module Support则是在驱动安装时你在机器上现场把模块源码编译成当前内核适配的.ko文件并且每次检测到新内核被安装时自动运行dkms install重新编译一遍。这是最“智能”的方案但前提是你的机器上有完整的编译环境包括linux-headers-$(uname -r)、gcc、make而且 NVIDIA 驱动源码本身要兼容新内核有时源码旧了新内核改了内部接口照样编译失败。在实际使用中Ubuntu 官方仓库里提供的nvidia-driver-535之类的包本质上就是通过 DKMS 来构建模块的。但很多人在装 NVIDIA 驱动时选择的是从 NVIDIA 官网下载.run文件手动安装选错了安装选项比如选了 Install and build kernel module only 或者用了预编译包又没有构建 DKMS 支持就会埋下后续脱节的雷。1.3 典型触发场景哪些操作最容易导致脱节根据我自己踩坑和帮人排障的经验以下三种操作最常触发“内核升级后显卡不可用”场景一Ubuntu 自动更新触发了内核升级。HWEHardware Enablement内核在 22.04 上会从 5.15 升到 6.5或者从 6.5 升到 6.8系统更新完提示重启重启后直接面临黑屏风险。大多数人不清楚 update manager 里的内核更新要配合驱动更新一起处理。场景二手动安装了主线内核mainline kernel。比如为了支持新硬件、修复 bug从 kernel.ubuntu.com 下载了 6.9 或 6.10 的 deb 包安装。这个行为会直接绕开 Ubuntu 的驱动管理机制因为新版内核通常超出了当前 NVIDIA 预编译模块的支持范围。场景三重装了 NVIDIA 驱动但只装了一半。例如先执行了sudo apt remove --purge nvidia-*卸载旧驱动然后直接下载官网驱动.run文件安装时选择了默认的预编译模块如果你用了--no-dkms参数或者安装器检测不到内核头文件时系统里就不会有这个新内核对应的模块。2. 定位问题三步确认你到底是“模块缺失”还是“模块不匹配”当我远程帮人排查时第一步永远是确认系统当前状态。别还没搞清问题就开始重装驱动那样大概率会浪费更多时间。以下是我在实际排障中沉淀出来的三步定位法。2.1 第一步确认当前内核版本与驱动包状态在终端登录字符界面能进就行如果图形界面起不来用 CtrlAltF3 切到 tty3执行uname -r这个命令输出的是你当前正在运行的内核版本比如6.5.0-15-generic。然后查一下系统里 NVIDIA 驱动包的版本dpkg -l | grep -i nvidia | awk {print $2, $3}如果你看到大量nvidia-dkms-535、libnvidia-gl-535之类的包版本号是535.xxx那说明驱动装的是 apt 版。如果没有任何输出说明驱动可能是用官网.run文件装的或者已经卸载了。再把 DKMS 状态也看一眼dkms status会出现类似下面的输出nvidia/535.154.05, 6.2.0-26-generic, x86_64: installed nvidia/535.154.05, 6.5.0-15-generic, x86_64: installed如果只有旧内核显示installed而新内核那一行没有或者显示built但没有installed基本上就可以判定是模块缺失。2.2 第二步查看内核日志确认 NVIDIA 模块加载失败的具体原因光知道模块缺失还不够因为“缺失”也有多种原因可能是 DKMS 没编译、可能是编译了但因为是预编译模块版本不支持新内核、可能是模块签名验证失败。这些都得靠日志来区分dmesg | grep -i nvidia journalctl -b -g nvidia|NVRM --no-pager常见的报错有以下几类每类的处理方向都不同NVRM: The NVIDIA GPU driver is not compatible with this kernel驱动源码和内核接口不兼容属于编译层面的问题。nvidia: version magic 6.5.0-15-generic should be 6.2.0-26-generic模块是新内核的但 depmod 用旧模块目录的路径或者模块加载顺序错了。MODSIGN: Module signature verification failedSecure Boot 开启模块没有正确签名。这在预编译模块场景中很常见因为预编译模块通常使用 NVIDIA 的签名密钥而 Ubuntu 默认 Secure Boot 环境下只信任 Ubuntu 自己的密钥和用户自己登记的 MOK 密钥。nvidia: Unknown symbol ...说明模块编译时对应的内核接口与当前运行内核不一致通常是用了旧内核的遗留文件强行加载。2.3 第三步区分是驱动层问题还是显示管理器Display Manager问题有些时候nvidia-smi能正常运行但是进不了桌面那就不是内核模块加载失败而是显示管理器gdm3、lightdm、sddm 其中之一配置问题或者 Xorg 配置指向了旧驱动路径。用这个命令快速检查nvidia-smi如果提示NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver.这就是明确的驱动层问题。如果nvidia-smi正常但systemctl status gdm3显示失败那就去看/var/log/Xorg.0.log或者/var/log/gdm3/下的日志找到类似(EE) NVIDIA(0): Failed to load the NVIDIA kernel module这样的提示这仍是驱动加载层问题如果是(EE) no screens found那可能是配置文件的 BusID 指向问题。把这三步走完问题大概能收敛到 80% 的准确度。到这一步我通常会拍板出一个结论究竟是驱动包没跟上、内核太新还是签名坏了。接下来对症下药。3. 对症下药三条恢复路径按优先级排列3.1 最稳妥的路径回到旧内核启动借助 Ubuntu 的更新机制把驱动和内核重新对齐如果你只是自动更新把内核升了想立刻恢复图形界面最省事的方法不是去拉着新内核编译驱动而是重启时在 GRUB 菜单里选“Advanced options for Ubuntu”进入子菜单选择旧内核比如6.2.0-26-generic启动。回归旧内核之后系统回到你之前熟悉的界面此时你有两条路可走直接在新内核环境下重装 NVIDIA 驱动使用sudo apt install --reinstall nvidia-driver-535这个操作会触发 DKMS 为当前内核重新编译模块。如果你不想折腾新内核有些新内核确实和旧版驱动不兼容尤其是 470 系列老驱动对接 6.5 内核时经常失败可以直接锁定内核版本不让它再自动升级sudo apt-mark hold linux-image-generic linux-headers-generic。我个人强烈建议优先使用 apt 重装驱动而不是去官网下载.run文件因为Ubuntu 的 apt 仓库里驱动和内核版本是经过 QA 的不容易出现模块与内核接口对不上的情况。用 apt 装驱动的完整步骤sudo apt update sudo apt install --reinstall nvidia-driver-535 sudo apt install --reinstall dkms sudo dkms autoinstall sudo update-initramfs -u sudo reboot注意“535”只是我举例需要根据你系统里已有的驱动版本确定Ubuntu 20.04 可能是 470 或 52524.04 可能是 535 或 550。执行apt list --installed | grep -i nvidia就能看到你之前用的版本号。选版本有个技巧优先选当前 Ubuntu 仓库里默认推荐的版本运行ubuntu-drivers devices会列出适合你 GPU 的推荐驱动版本以它为准。3.2 如果 apt 重装失败尝试用 DKMS 手动为当前内核构建模块在某些情况下apt install --reinstall不会触发重新编译因为模块包已经在系统里标记为 installedapt 可能直接跳过编译步骤。这时手动执行 DKMS 构建sudo dkms remove nvidia/535.154.05 --all sudo dkms install nvidia/535.154.05 -k $(uname -r)如果 DKMS 源码目录里没有该版本先确认nvidia-dkms-535包是否安装dpkg -L nvidia-dkms-535 | grep -i .tar\|source源码通常在/usr/src/nvidia-535.154.05/下DKMS 默认会读取这个目录做编译。如果没有源码目录那就先apt install nvidia-dkms-535把它装全。编译时最常遇到的问题就是缺少内核头文件。版本不对会直接报kernel header files not in /usr/src/linux-headers-6.5.0-15-generic之类的错误解决方式sudo apt install linux-headers-$(uname -r)Ubuntu 20.04/22.04 上还可能要额外装build-essential和gcc因为 DKMS 编译过程需要完整工具链只装了裁剪版系统的机器经常会漏掉。编译完成后用dkms status验证看到nvidia/535.154.05, 6.5.0-15-generic, x86_64: installed这一行就说明二进制模块已经生成到位。之后再执行sudo update-initramfs -u更新 initramfs重启测试。3.3 新内核太新驱动源码本身不支持走 N卡闭源驱动的官方 runfile 安装路线如果新内核版本过新比如你装了 mainline 6.8 rc 或者 6.10连 NVIDIA 的官方驱动源码都还没适配DKMS 编译也会失败报错信息五花八门比如error: ‘VM_IO’ undeclared、unknown type name ‘vm_fault_t’之类。这时候只能用 NVIDIA 官方发布的最新版本驱动.run文件因为 NVIDIA 通常会在驱动发布时修复内核兼容性。去 NVIDIA 官网驱动下载页面根据显卡型号搜索对应驱动下载.run文件后执行chmod x NVIDIA-Linux-x86_64-550.xx.run sudo ./NVIDIA-Linux-x86_64-550.xx.run安装器会让你选择是否安装 DKMS这时建议选“Yes”同时选择“Install and build kernel module for current kernel”。如果你不确定安装器怎么交互也可以加参数以非交互方式执行sudo ./NVIDIA-Linux-x86_64-550.xx.run --silent --dkms注意在执行.run安装前强烈建议先彻底卸载掉之前 apt 装的 NVIDIA 驱动不然两套驱动会互相踩sudo apt purge *nvidia* *cuda* sudo apt autoremove.run安装器一般也会帮你清理旧模块但你主动清一遍更稳妥。关于预编译模块还有一个细节NVIDIA 官网驱动下载页面实际上为 Debian/Ubuntu 提供了 “deb” 安装方式这些 deb 包由 NVIDIA 官方打包仓库地址是https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/里面会提供nvidia-driver-550之类的预编译 deb 包也依赖 DKMS。但这套包经常比 Ubuntu 仓库里的新对较新内核的支持也更好。如果你用 Ubuntu 仓库的驱动编译失败可以先试试切到 NVIDIA 官方仓库装新驱动。4. 灾难恢复进阶玩家的抢救方案与长期防复发4.1 当所有常规手段都无法进入系统时的操作顺序有些倒霉的情况是你在新内核下连 tty 都进不了或者 tty 能进但网络不通比如网卡驱动也是 DKMS 模块跟着内核一起崩了。这时候需要另外一台电脑或者 U 盘用 Ubuntu Live USB 启动进入临时系统后挂载硬盘分区根分区和 /boot/efi用chroot进入原系统。在 chroot 环境里执行apt purge nvidia-*彻底卸载驱动让系统先回到 NVIDIA 开源驱动 nouveau 的状态虽然 nouveau 性能拉胯但至少能出画面。再按上一节的方法重装 NVIDIA 驱动。chroot 的简化流程sudo mount /dev/sdaX /mnt sudo mount /dev/sdaY /mnt/boot/efi sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo chroot /mntchroot 之后执行mount -t proc proc /proc mount -t sysfs sys /sys mount -t devtmpfs dev /dev apt purge *nvidia* apt install nvidia-driver-550 update-initramfs -u exit注意sdaX、sdaY 要根据你机器实际分区替换用lsblk -f查看。4.2 Secure Boot 与模块签名一个特别容易忽略的坑如果你开启了 Secure Boot即使 DKMS 编译成功内核也拒绝加载那些没有签名的模块。Ubuntu 在安装 NVIDIA 驱动时会自动弹出 MOKMachine Owner Key设置界面让你设置密码后在重启时确认导入密钥。很多人没设置或者密码忘了结果驱每次装完都加载失败。检测方法mokutil --sb-state输出SecureBoot enabled就需要处理。Ubuntu 的 DKMS 机制会在编译时自动用mokutil --import注册 MOK 密钥前提是在安装驱动时你设过密码。如果你当前系统里没有对应的 MOK 密钥可以在 chroot 或者正常系统里重新生成并导入sudo mokutil --import /var/lib/shim-signed/mok/MOK.der输入一个临时密码重启后进入 MOK 管理界面选择 Enroll key from disk选中 MOK.der输入刚才的密码再确认重启就完成了。这个步骤每个新手都该记下来因为它直接影响你能不能用新购买的笔记本自带的 OEM Windows Ubuntu 双系统环境原生开 Secure Boot 的机器非常普遍。4.3 构建一份长期防复发的维护清单踩坑踩多了我现在给自己维护机器的原则是“内核升级前先确认驱动兼容性驱动升级前先备份现状”具体如下定期检查内核版本驱动版本匹配状态推荐做一个check-nvidia.sh小脚本每次重启后自动跑一遍把uname -r和dkms status的结果写入日志有异常就发通知。使用 apt 的 hold 锁定内核版本在确认显卡驱动不需要更新的前提下锁定当前内核稳定版本。等 NVIDIA 驱动发布新版后再解锁升级内核并同步升级驱动。永远保留至少一个旧内核作为回退点。Ubuntu 默认保留两到三个版本的内核别手动删/boot/vmlinuz-*图省事。新内核不稳定时重启选 GRUB 的 Advanced options 就能回到能正常工作的旧内核。定期更新 DKMS 和驱动版本别半年不更新然后一次更新把内核和驱动全体都换新。频繁小步更新比大跨度跳跃安全得多。4.4 一次典型的完整抢救案例我可以分享一个实际发生的案例让大家对整个流程有更直观的理解。一位群友使用的 Ubuntu 22.04 系统某天自动更新后重启发现图形界面起不来只剩光标闪动。远程指令让他按 CtrlAltF3 进入 tty执行uname -r显示6.5.0-15-generic然后dkms status显示nvidia/535.154.05, 6.2.0-26-generic, x86_64: installed只有旧内核有模块。确认问题后第一件事是执行sudo apt install linux-headers-6.5.0-15-generic build-essential sudo dkms install nvidia/535.154.05 -k 6.5.0-15-generic结果编译报错提示驱动源码和 6.5 内核的某个头文件不兼容。这时直接换方案去 NVIDIA 官方仓库安装了 550 版本驱动这个版本已经支持 6.5 内核。执行sudo apt purge *nvidia* sudo apt install nvidia-driver-550因为 Secure Boot 是开着的重启进入 MOK 界面导入了新密钥。重启后nvidia-smi正常输出图形界面恢复。整个过程耗时大约 40 分钟包括等编译的时间。如果直接走 Grasp 旧内核回退并锁版本可能 10 分钟就结束了。从这个案例里能学到的核心经验是先花两分钟判断“旧内核是否可用”如果可用就直接回退别恋战新内核只有确认非上新内核不可时才去硬刚驱动编译。5. 常见问题速查一张表解决 80% 的困惑我把平时遇到的高频问题整理成一张速查表方便你在排障时快速定位。症状可能原因快速处理命令重启后进不了图形界面只能进 tty新内核下 NVIDIA 模块缺失或加载失败uname -r确认内核版本dkms status看模块状态回退旧内核或重装驱动nvidia-smi报错 couldnt communicate with the NVIDIA driver内核模块未加载sudo modprobe nvidia失败则查dmesg | grep NVRMDKMS 编译报错 kernel header files not in缺少内核头文件sudo apt install linux-headers-$(uname -r)Secure Boot 开启导致模块加载失败MOK 密钥未导入mokutil --sb-state检查状态重新导入 MOK 密钥编译报错 VM_IO undeclared驱动版本太老不支持新内核换用更新的 NVIDIA 驱动版本550或者回退内核驱动包重装后 DKMS 还是没编译apt 缓存或标记问题sudo dkms autoinstall强制安装所有待编译模块卸载 apt 版 NVIDIA 驱动后系统仍然有 nvidia 模块存在存在.run安装残留ls /lib/modules/$(uname -r)/kernel/drivers/video/nvidia/手动清理或重跑驱动安装器用--uninstall选项nvidia-settings找不到了启动器按钮消失驱动安装不完全或者版本不匹配sudo apt install nvidia-settings重新安装确认驱动版本一致Ubuntu 24.04 安装 NVIDIA 驱动时提示 No such file or directory 关于 dkms.conf驱动源码路径被清理重新执行sudo apt install --reinstall nvidia-dkms-550然后手动执行dkms autoinstall注意最后那条“ubuntu 24.04 lts apt源”相关的热词提示其实 Ubuntu 24.04 的 apt 源默认已经是 NVIDIA 驱动适配的第一选择只要能连通官方源用ubuntu-drivers devices推荐的版本就最稳。6. 最后的经验之谈内核升级前必须做的一件事绕了一大圈其实最核心的废话就是这句话升级内核前先确认你的 NVIDIA 驱动版本是否支持目标内核。具体来说每次 Linux 内核大版本发布如 5.15 升到 6.56.5 升到 6.8NVIDIA 都会在驱动发布说明里列明支持的内核范围。Ubuntu 的 HWE 内核在升级时如果你用的是nvidia-driver-535默认支持范围内通常没事但如果你锁定在了 470 系列老显卡用户很常见而 HWE 内核跳到 6.5那几乎必然会出问题。我的个人习惯是在新内核候选版本出现在更新列表里时先跑一次apt changelog linux-image-generic确认内核变更范围和 bug 修复方向如果没问题再执行sudo apt update sudo apt upgrade升级之后立刻再看一眼dkms status如果 DKMS 已经在新内核目录下自动编译好了模块说明驱动包自带的 DKMS 配置足够新重启基本安全。如果没有自动编译那就别急着重启趁现在还在旧内核环境下把驱动和内核头文件补齐、手动编译好再重启。尤其是现在很多新笔记本都出厂预装 Windows 和 Ubuntu 双系统新硬件的 Linux 内核支持本来就在跟进阶段NVIDIA 对最新内核的适配也经常是滞后的。在这种情况下更不建议追求“最新内核”优先使用 Ubuntu LTS 默认内核版本比如 24.04 的 6.8 内核等 HWE 或者 Ubuntu 官方在后续点版本中升内核时再同步升级驱动。排障这件事本质上就是快速确定问题在哪一层选择合适的绕行路线而不是每次都开膛破肚。希望这篇文章能帮你省下周末下午的时间直接从“显卡黑屏”的坑里爬出来。
返回列表