LOADING

加载过慢请开启缓存 浏览器默认开启

DRM 半瘫故障排查与修复总结:QXL 显卡 TTM 死锁

2026/8/31 0 技术 3.5k 字 · 约 13 分钟 故障排查 Linux 虚拟化

日期:2026-08-31
对象:VM 801(Arch Linux,内核 7.1.5-arch1-2)
结论:根因是 QXL 虚拟显卡 的 TTM 显存管理异常导致关机路径 drm_modeset_lock 死锁,连坐 systemd PID 1;修复为换用 virtio-gpu。

一、现象

  • 系统”半瘫痪”:Hermes 网关、SSH 都在跑,但 systemctl 全部挂死/超时
  • SSH 新会话登录失败,报”传输端点未连接”
  • 内核 hung task 报告:systemd:1 blocked for more than 1228s,栈在 drm_modeset_lock,进程状态 D(不可中断睡眠)

二、排查过程

  1. 先疑 sshd 未运行——拉起后连接恢复,但 systemctl 依旧瘫痪
  2. 怀疑 D-Bus/套接字缺失——实测四个关键套接字全部连通,排除
  3. 最终定位:/proc/1/wchan 显示 PID 1 卡在 drm_modeset_lock,hung task 阻塞时间 245s → 1228s 递增后被抑制

关键证据(journalctl -b -1)

时间 事件
8/8 01:50 起 TTM Buffer eviction failed 持续爆发:8/8 一天 5193 次、8/9 75 次,整个 boot 共 5608 次
8/31 05:31:40 root 从 172.16.15.17(宿主机网段)SSH 登录
05:31:51 执行 shutdown(logind: poweroff requested from client PID 289246)
05:35:26 起 TTM eviction failed 密集出现(当天 340 次),关机流程走显示路径
05:35:53 systemd PID 1 blocked,hung task 报告 21 条,1105s→1228s 后抑制
05:31–06:58 hermes 进程持续运行、网络存活——“看着活着”
06:58:53 VM 终结,07:00:22 重启恢复

三、根因

  • 本 VM 显卡为 QXL 虚拟显卡qxl 驱动,16M VRAM + 64M surface),非 i915
  • qxl 的 TTM 显存管理持续异常(eviction failed 从开机第二天即出现,5608 次)
  • 8/31 05:31 的 shutdown 关机流程(停 Graphical Interface、显存回收)触发 drm_modeset_lock 死锁
  • systemd PID 1 撞锁永久阻塞(D 状态,SIGKILL 无效),整个管理栈失效
  • 此前误判为宿主机 i915 驱动锁死——错误。宿主机 5 个 boot 全部干净,i915 从未是故障源

四、修复

qm shutdown 801        # 优雅关机(修复前该路径必卡死)
qm set 801 --vga virtio # qxl → virtio-gpu
qm start 801

五、验证(三层全部通过)

  1. 结构lsmodvirtio_gpu,无 qxl/dev/dri/card1 + renderD128;本 boot 内核日志 0 条 TTM/hung task/drm_modeset_lock
  2. 行为:完整关机-重启循环,优雅关机 10.7 秒 完成(修复前:卡死 87 分钟被迫强制重启),连续两次通过
  3. 基线:systemd running,hermes-gateway / sshd 均 active,日志零异常

六、后续

  • 本机内核 7.1.5 可随时 pacman -Syu 升级观察(独立于本次修复)
  • 其他 VM 扫描:仅 115 (Win-xp) 用 qxl,但 Windows guest 走厂商驱动、不经 Linux TTM 路径,无同类风险,维持现状
  • 若文档化监控:journalctl --since "1 day ago" | grep -cE "TTM.*eviction failed|hung task|drm_modeset_lock" 应持续为 0

附录:错误结论作废声明

  • i915.enable_guc=0:无效(VM 内无 i915)
  • modprobe.blacklist=i915:无效(同上)
  • “唯一路径 sysrq”:仅对物理机成立;VM 可直接 qm reset