一套新的设备,CPU使用的是 J1800,跑公司的产品出现了重启失败的情况,排除了是服务没正常退出的问题。也确认了之前的硬件配置上不会出现这个问题。因为产品跑的是 Debian10 的 Linux 系统,所以安装了一个全新的 Debian10 来做测试,也会出现重启卡死的现象。为了解决这个问题,进行了排查,并写下这篇文章做一下记录,方便以后其它问题的调试,和方便遇到同样问题的人。

解决方法

先说最后的解决方法,在 bios 中,修改 OS Selection 类型为 Windows 8.x,即可解决问题。

这个解决方法是在网上搜到的,网上能找到好几篇说自己用的 CPU 是 J1900 遇到了这个问题,最后通过上面说的修改 bios 方法解决了问题,虽然 CPU 不是完全一样,但应该J开头的 CPU 都有相同的毛病。

排查过程

因为之前同事已经折腾过,所以可以肯定排除了服务没退出导致无法正常关机的情况。我尝试查看了当输入 reboot 后的情况,无法重启的现象并非必现,是一种时不时能正常重启,时不时不行的情况。当无法重启时,终端显示 watchdog: watchdog0: watchdog did not stop! 同时屏幕卡死,意思是连光标也不闪了,同事研究过并非 watchdog 导致无法重启。光标不闪让我感觉可能是图形上出了问题,所以首先我在 Linux 启动参数中加上 nomodeset 的参数,这次卡死后,光标依然能正常闪烁,但依然会一直卡住无法重启。下一步我的想法是让终端输出更多的日志,好排查问题。内核日志是分输出级别的

等级 类型 描述
0 (KERN_EMERG) system is unusable
1 (KERN_ALERT) action must be taken immediately
2 (KERN_CRIT) critical conditions
3 (KERN_ERR) error conditions
4 (KERN_WARNING) warning conditions
5 (KERN_NOTICE) normal but significant condition
6 (KERN_INFO) informational
7 (KERN_DEBUG) debug-level messages

默认终端应该只会打印4以下级别的内核日志。有一个方法查看和临时修改打印的日志级别就是查看和修改文件 /proc/sys/kernel/printk

1
2
[root@localhost ~]# cat /proc/sys/kernel/printk
4       4       1       7

4个数字分别代表如下:

  1. 控制台日志级别:优先级高于该值的消息将被打印至控制台。
  2. 缺省的消息日志级别:将用该值来打印没有优先级的消息。
  3. 最低的控制台日志级别:控制台日志级别可能被设置的最小值。
  4. 缺省的控制台:控制台日志级别的缺省值。

我直接把4个数值都设为8,让终端尽可能多的打印日志

1
[root@localhost ~]# echo '8 8 8 8' > /proc/sys/kernel/printk

这样设置后,当重启卡死时,卡在的地方是

1
sd 1:0:0:0 [sda] Synchronizing SCSI cache

在没有卡死的情况下,上面那句之后会打印多如下的内容,并最终重启成功

1
2
3
reboot: Restarting system
reboot: machine restart
ACPI MEMORY or I/O RESET_REG

我查过 Linux 的重启原理,通过对 CPU 某个针脚发送电信号来达到重启的功能,而我查看过源代码这种操作是在日志 reboot: Restarting system 之后。 查到这里我认为这个重启时不时失效的情况,并不是硬件重启相关的操作导致无法重启,而是内核执行重启模块操作之前的某个操作卡死导致的无法重启。下一步我准备通过添加日志重编内核,或者使用 kprobe 方式来进行更深入的调试,不过因为途中我已经找到了通过修改 bios 能解决问题,没继续进行更多的排查。

另一种重启方法

在查看解决方法时,找到了一种使用sysrq来重启的方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
reboot.sh:
#!/bin/sh
echo 1 > /proc/sys/kernel/sysrq
echo u > /proc/sysrq-trigger
sync
echo b > /proc/sysrq-trigger

poweroff.sh:
#!/bin/sh
echo 1 > /proc/sys/kernel/sysrq
echo u > /proc/sysrq-trigger
sync
echo o > /proc/sysrq-trigger

这种方法能重启成功,也说明了并非硬件在重启上出了问题,而是其它地方导致。我也是第一次知道原来键盘是有sysrq这个键,就在insert键上方。上图的命令例如 b 是重启,那对应在键盘上按下 alt+b+sysrq 也能实现重启。我试过按上述按键重启,要多尝试才知道按的方法,顺序不对会失败。但上面的重启方法并不会正常停止服务,所以非必须的话,不应该直接使用。