systemctl restart gdm3 卡住排查:gpu-manager 阻塞在 QXL 的 drm_master_open
九月 12, 2026 [Linux 与系统] #gdm #systemd #ubuntu现象
本机(Ubuntu 24.04 虚拟机,QEMU/KVM + QXL 虚拟显卡)执行:
sudo systemctl restart gdm3
命令长时间不返回,终端像卡死;Ctrl-C 之后重跑还是卡。
时间线:卡在 gpu-manager,不是 gdm3
journalctl -u gdm3 把两次 restart 的时间线拉出来:
22:14:13 systemd[1]: Stopping gdm3.service - LSB: GNOME Display Manager...
22:14:33 systemd[1]: Stopped gdm3.service - LSB: GNOME Display Manager. ← stop 花了 20s
22:14:33 systemd[1]: Starting gpu-manager.service - Detect the available GPUs...
22:16:36 systemd[1]: Finished gpu-manager.service - Detect the available GPUs...
22:16:36 systemd[1]: Starting gdm3.service - LSB: GNOME Display Manager... ← 等 gpu-manager 结束才开始
22:16:36 systemd[1]: Started gdm3.service - LSB: GNOME Display Manager. ← gdm3 本身瞬间完成
第二次同样:
22:20:58 Stopped gdm3.service
22:22:30 Finished gpu-manager.service ← 1m32s
22:22:30 Started gdm3.service
耗时几乎全部花在 gpu-manager.service 上:gdm3 的启动在等它跑完。
顺带一个容易误判的点:Ctrl-C 只会结束 systemctl 客户端进程,systemd 里的 job 仍在继续。本机第一次 restart 的客户端进程在 22:16:22 就退出了,而 job 到 22:16:36 才真正完成——所以"Ctrl-C 没反应"只是假象,实际是 job 还没跑完。
依赖链:restart gdm3 为什么会拉起 gpu-manager
gpu-manager.service 由 Ubuntu 的 ubuntu-drivers-common 提供(检测 GPU 变化、处理显卡驱动切换),它的单元声明:
# /usr/lib/systemd/system/gpu-manager.service
[Unit]
Before=display-manager.service
...
[Install]
WantedBy=display-manager.service
而 display-manager.service 在本机是指向 gdm3 的别名,安装时生成的 wants 链接把它绑进了 display-manager 的启动事务:
$ ls /etc/systemd/system/display-manager.service.wants/
gpu-manager.service -> /lib/systemd/system/gpu-manager.service
$ systemctl show gdm3 -p Wants,After
Wants=gpu-manager.service
After=... gpu-manager.service
于是每次 start/restart gdm3:systemd 先按依赖拉起 gpu-manager,又因为 Before=display-manager.service,gdm3 的启动必须排在它后面——gpu-manager 不结束,gdm3 就不会开始。
实锤:单跑 gpu-manager 也卡,卡在内核 drm_master_open
单独跑 gpu-manager,同样不返回:
$ time timeout 40 /usr/bin/gpu-manager --log /tmp/gm-test.log
real 0m48.337s
user 0m0.042s ← 几乎不耗 CPU
sys 0m0.033s
rc=124 ← 被 timeout 杀掉
CPU 只有 0.04 秒,说明它在等而不是在算。抓卡住时的进程状态与内核栈:
$ grep State /proc/<pid>/status
State: D (disk sleep) ← 不可中断睡眠
$ cat /proc/<pid>/wchan
drm_master_open
$ cat /proc/<pid>/stack
[<0>] drm_master_open+0x2b/0xc0
[<0>] drm_open_helper+0x109/0x130
[<0>] drm_open+0x76/0x130
[<0>] drm_stub_open+0xb3/0xf0
[<0>] chrdev_open+0xcf/0x250
[<0>] do_dentry_open+0x21d/0x570
[<0>] vfs_open+0x33/0x50
gpu-manager 在打开 /dev/dri/card1(QXL 显卡的 DRM 设备)时阻塞在内核 drm_master_open:进程处于 D 状态(不可中断),信号也打不断。它的业务逻辑其实已经跑完(日志里 Skipping /dev/dri/card1, driven by qxl → Single card detected),卡的只是这次 open 系统调用。约 1.5~2 分钟后自行解除(两次实测 2m03s / 1m32s),具体是谁持有内核锁没有继续深挖——定位到这一步,修复方向已经清楚。
本机特例:gdm3 其实已经不存在
这台机器上 gdm3 包早已被移除(dpkg -l gdm3 状态为 rc,只剩配置文件),/usr/sbin/gdm3 不存在;残留的 /etc/init.d/gdm3 被 systemd 生成成 gdm3.service,而脚本开头是:
DAEMON=/usr/sbin/gdm3
test -x $DAEMON || exit 0 ← 二进制不存在,start 直接退出 0
所以等完 gpu-manager 那 2 分钟,GDM 也不会真的启动——unit 显示 Started 只是 init 脚本空转退出 0。这个 restart 除了等 2 分钟之外什么也没发生。
(这也说明判断"服务起没起"不能只看 systemctl status 的 Active 状态,要看进程是否真的存在。)
2026-09-13 更新:本节记录的是当时的残留状态。桌面栈已重装(起因见文末「背景补记」),gdm3 现在是原生
gdm.service,这个特例已不存在。
修复方案(2026-09-13 实测:方案 1 生效)
按场景选:
-
还在用 GDM:屏蔽 gpu-manager 即可——
sudo systemctl mask gpu-manager.serviceQXL 虚拟机上 gpu-manager 没有用途(它服务于 NVIDIA/AMD 专有驱动切换);mask 后
Wants依赖会立即失败,gdm3 照常启动(Wants 非强制)。需要时systemctl unmask恢复。本机 2026-09-13 实测:mask 后安装/启动 gdm3 均无卡顿,2 分钟等待消失。 -
不用 GDM:清掉残留,避免再踩——
sudo apt purge gdm3 # 清 /etc/init.d/gdm3 + /etc/X11/default-display-manager sudo systemctl daemon-reload -
只想命令别卡:
systemctl restart gdm3 --no-block(立即返回,但实际启动仍要等 gpu-manager)。 -
也可用 drop-in 摘掉依赖,但不如 mask 直接。
2026-09-13 后续:桌面栈重装、QXL 显存耗尽
背景补记:桌面栈为什么"已经不存在"
07-24 的一次清理是起因:
Commandline: apt purge --autoremove snapd libsnapd-glib-2-1
Purge: ... ubuntu-desktop, ubuntu-desktop-minimal, gnome-shell, gdm3, ubuntu-session, gnome-remote-desktop, gnome-control-center ...
ubuntu-desktop 依赖的 firefox/thunderbird 是 snap 过渡包,过渡包依赖 snapd——--autoremove 顺着依赖链把整个桌面栈连坐了。表现:dpkg -l 里 gnome-shell/gdm3 全是 rc、/usr/share/xsessions 消失、控制台只剩 tty1 文本登录。
重装(在 mask gpu-manager 之后执行):
sudo apt-get update && sudo apt-get install -y gdm3
# 79 新装 + 28 升级,含 gnome-shell/ubuntu-session/gnome-remote-desktop/gnome-control-center
教训:apt purge --autoremove 删基础包(如 snapd)前先 apt-get -s 模拟看 Remove 列表;snap 过渡包会把删除面放大成桌面级事故。
新坑:QXL 显存 BO 耗尽,greeter 起了但画不出来
重装后 gdm.service active、gnome-shell 进程也在(日志已到 Registering session with GDM),但 VM 控制台仍是 tty1 文本。内核日志在刷:
[drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BO
[TTM] Buffer eviction failed
qxl 0000:00:01.0: object_init failed for (4096, 0x00000001)
每 ~15 秒一次,且从当天 17:55 就开始(远早于重装)——QXL 显存被更早的某次图形操作耗尽后状态粘住,重启 VM 复位后 GDM 登录界面正常渲染。
至此这台机器的 QXL 集齐了三种形态:drm_master_open 阻塞(gpu-manager)、没有 renderD128(纯 2D 卡)、显存 BO 耗尽(本次)。最终按 工具链迁移 Wayland 一文的实测方案把显卡换成 virtio-vga-gl,QXL 相关问题整体消失。
总结
systemctl restart gdm3卡住 ≠ gdm3 卡住:是gpu-manager.service被display-manager.service.wants拉进事务,且Before=display-manager.service,gdm3 的启动全程等它;- gpu-manager 卡在内核
drm_master_open(打开 QXL 的/dev/dri/card1,D 状态,约 2 分钟后自行解除),单跑可复现,与 gdm3 无关; - Ctrl-C 杀不掉卡住的 restart:只结束 systemctl 客户端,systemd 的 job 照跑;
- 排查套路:journal 时间线定位"谁在等谁"→ 单元依赖(
systemctl show -p Wants,After)→ 单跑复现 →/proc/<pid>/wchan+/proc/<pid>/stack拿内核栈; - 本机 gdm3 曾 remove(rc)、init 脚本
test -x空转(2026-09-13 已重装为原生gdm.service);mask gpu-manager 实测生效; - 后续新坑:桌面栈被
apt purge --autoremove snapd连坐移除;QXL 显存 BO 耗尽会让 greeter"起了但画不出",重启复位;根治是换virtio-vga-gl(实测见「工具链迁移 Wayland」那篇)。
排查命令速查
| 目的 | 命令 |
|---|---|
| 看 restart 卡在哪个阶段 | journalctl -u gdm3 --since "5 min ago" -o short-precise |
| 看单元依赖(谁拉起谁、谁等谁) | systemctl show <unit> -p Wants,After,Before |
| 看依赖安装链接 | ls /etc/systemd/system/display-manager.service.wants/ |
| 单跑复现 + 计时 | time timeout 40 /usr/bin/gpu-manager --log /tmp/gm.log |
| 卡住进程的内核栈 | cat /proc/<pid>/wchan; cat /proc/<pid>/stack |
| 看 systemd 当前 job | systemctl list-jobs |