环境: Ubuntu 24.04 / 26.04,机器是 7 卡 GPU 服务器(SSH 进去操作),装了 GNOME + gdm 但本地无人使用图形界面。
sudo apt install nvidia-driver-590 跑完,新驱动文件已经在盘上,但内核里跑的还是旧的 nvidia.ko——nvidia-smi 显示的还是旧版本。重启自然能解决,但如果机器正在挂着大模型 / 别的训练任务,30 秒重启 = 必丢的进度;反过来,如果窗口干净,内核模块热替换其实只要几条命令。
这篇记录一次实际操作:从 7 卡机器上把驱动从旧版热切到 590,过程中遇到的占用、误判,和应该回头走 reboot 的边界。
前提:GPU 必须"完全空"
热加载的核心阻碍是 rmmod nvidia* 要把内核模块卸下来,只要还有任何进程在引用,就会 Module is in use。所以第一件事是定位占用:
sudo lsof /dev/nvidia*
sudo fuser -v /dev/nvidia*
lsmod | grep nvidia
我这台机器上第一次跑出来是这样:
COMMAND PID USER FD TYPE DEVICE
gnome-she 2979 gdm mem CHR 195,255 /dev/nvidiactl
gnome-she 2979 gdm mem CHR 195,0 /dev/nvidia0
gnome-she 2979 gdm mem CHR 195,1 /dev/nvidia1
... (一直到 nvidia6,7 张卡全占了)
占用者是 gdm 的 gnome-shell——登录界面在用所有卡。本地物理上没人用桌面,但 gdm 拉起的 greeter 仍然把 GPU 全占了。
释放占用:停 gdm,而不是杀进程
直接 kill gnome-shell 会被 systemd 拉起来,正确做法是停掉它的服务:
sudo systemctl stop gdm
如果是多卡 NVLink 机器还要停这两个:
sudo systemctl stop nvidia-fabricmanager 2>/dev/null
sudo systemctl stop nvidia-persistenced 2>/dev/null
再确认一次,期望全空:
sudo fuser -v /dev/nvidia* # 应该没输出
lsmod | grep nvidia # 各模块 Used by 应该为 0
正常应该看到类似:
nvidia_uvm 2076672 0
nvidia_drm 135168 0
nvidia_modeset 1638400 1 nvidia_drm
nvidia 104071168 2 nvidia_uvm,nvidia_modeset
注意 nvidia_modeset 的 Used by=1 是 nvidia_drm 引用的,nvidia 的 Used by=2 是 uvm / modeset 引用的——这些都是模块之间的内部依赖,不算用户态占用,可以卸。
卸载顺序很重要
按依赖关系从叶子到根卸:
sudo rmmod nvidia_uvm
sudo rmmod nvidia_drm
sudo rmmod nvidia_modeset
sudo rmmod nvidia
顺序反了会立刻报 Module is in use——比如先 rmmod nvidia 会因为还有 uvm / modeset 引用而失败。
加载新驱动:按依赖正序
刚才反过来:
sudo modprobe nvidia
sudo modprobe nvidia_uvm
sudo modprobe nvidia_modeset
sudo modprobe nvidia_drm
7 卡机 modprobe nvidia 那条会做卡的初始化,大约等几秒,第一次 nvidia-smi 也会稍慢——正常。
验证
nvidia-smi # 顶部 Driver Version 应是 590.x
cat /proc/driver/nvidia/version
如果是要继续用图形登录,把 gdm 拉回来:
sudo systemctl start gdm
几种"看起来空了实际没空"
lsmod的 Used by 不是 0,但fuser看不到占用:典型是有 CUDA 进程已退出但内核里 GPU 状态还没释放(常见于训练异常崩了)。这时rmmod还是会失败,别用--force——强行卸有不小概率把内核搞挂,只能 reboot。nvidia-persistenced偷偷拉起来:有些发行版默认 enable,即便你停了它 systemd 也可能在重新加载模块时自动 restart。先systemctl mask nvidia-persistenced,操作完再 unmask。- VFIO / vfio-pci 接管了某张卡:做过 GPU 直通到虚拟机的机器会有这个。
lspci -nnk | grep -A3 NVIDIA看驱动绑定,如果显示Kernel driver in use: vfio-pci,那张卡跟 nvidia.ko 无关,不影响热替换,但要记得lsmod看到 nvidia 模块 Used by 可能反映不出来。 - container runtime 持有 device cgroup:Docker / containerd 拉起过
--gpus all的容器后,即便容器停了 cgroup 里有时还残留对/dev/nvidia*的引用。docker ps -a全清一下。
什么时候直接 reboot 更省心
- 机器跑着图形会话有人在用:停 gdm 等于把人桌面踢了,跟重启没区别。
- 占用清不掉:reboot 是干净的兜底。
- 大型多卡 + NVLink + FabricManager:热加载失败可能导致部分卡状态半死,排查比 reboot 贵得多。
- 不确定上层服务能不能自动拉起:reboot 一次性把所有 systemd unit 按依赖顺序起一遍,反而稳。
我自己的习惯:如果机器没在跑长任务,直接 reboot(30 秒 vs 折腾 5 分钟还不一定成);如果有长任务,先等 checkpoint 落盘再说,别为了"省一次重启"赌驱动状态。
回滚 / 出问题
如果 modprobe 后 nvidia-smi 报错或卡进半死状态,不要硬撑——立刻 reboot。最坏情况:
- 物理通道:IPMI / BMC console
- 远程通道:
echo b > /proc/sysrq-trigger(需要 sysrq 启用)
操作前留个版本快照(nvidia-smi --query-gpu=driver_version --format=csv),万一回退方便对比。
小结
NVIDIA 驱动热加载不是"魔法替代 reboot",而是"知道占用模型之后的一种省事手段"。流程其实就三步:停掉占 GPU 的所有东西 → 按依赖逆序 rmmod → 按依赖正序 modprobe。但凡有一点不干净,reboot 更便宜。