Linux 启动问题分析
ssk-wh Lv5

启动后光标一直闪烁

在grub引导项点击确认后,之后系统一直处于光标闪动的状态.

image

这种情况,根据经验推测,可能是 /boot 目录下的 initrd 文件未被正确找到或加载。首先应检查 GRUB 引导参数中 initrd 相关配置是否存在错误。在 GRUB 菜单中,按 e 键进入引导参数编辑页面,仔细查看以 initrd 开头的那一行内容,确认其路径和文件名是否准确无误。initrd 是一个临时的根文件系统,内核在启动后会将其挂载,它在内核启动的早期阶段提供必要的驱动程序和工具,以便内核能够顺利访问实际的根文件系统。

针对此类问abbrlink题,可以在 GRUB 参数编辑页面中,在以 linux 开头的那一行末尾添加 "debug" 参数。若内核因找不到 initrd 而触发 panic,其报错内容大致如下:

image

上图可以明显看到rootfs 无法挂载,这种情况,只需分析为何找不到 initrd 的原因即可.

启动后卡住

有时候系统启动后会卡在某个服务上,屏幕上只显示系统 logo 闪烁,而看不到相关日志。这种情况下,可以删除 GRUB 参数中的 quiet splash,以便查看详细的启动日志

image

如果希望进一步查看内核日志,可以将 loglevel 参数的值设置为最高级别(7,0 是最低级别)。在 GRUB 菜单中,按 e 键进入引导参数编辑页面,然后在 linux 开头的行中添加 loglevel=7 参数,最后按 F10 键加载引导信息,即可看到更详细的日志信息。

image

找不到 init进程

如果开机后能看到 GRUB 引导项,但系统无法正常启动,通常问题不大。

image

选中对应的引导项,按 e 键进入引导参数编辑页面。

image

如果系统在确认引导项后卡死,或者进入 initramfs 的 shell 页面,需要具体分析问题。例如,当系统实际的 / 无法找到时,通常会在 initramfs 阶段进入 busybox 内置的 shell 环境。

image

在这种情况下,可以查看内核参数,确认是否存在参数错误。例如,在 GRUB 编辑页面中,ostree= 参数的值被我故意在最后添加一个字母,从而让系统启动出错,方面展开接下来的排错过程。

image

此时,需要确认对应的目录是否存在。注意,ostree 参数的值通常需要以 /root/persistent 为前缀,之所以如此,当然是因为我提前看过initrd中对 ostree 参数的处理啦。

image

该问题源于系统启动过程中检查的checkouta目录不存在,而实际正确的目录名称应为checkout,这导致系统启动失败。
在排查类似问题时,建议在内核参数中添加debug选项,以获取 initramfs 初始化阶段的详细调试信息。

image

之后按下 F10,加载引导信息,当前这里的checkout我仍然修改为checkouta,方便我们复现问题并分析,不出意外,我们又来到了熟悉的页面

image

在 initramfs 的 shell 中,可以通过查看 /run/initramfs/initramfs.debug 文件来分析日志。日志文件中包含了详细的启动过程信息,通过查看日志可以找到报错的地方。

image

这里都是熟悉的 bash 脚本,相信阅读对大家来说不会产生障碍,接下来就是找到报错的地方

(initramfs 中存在许多天然断点,这些断点可以通过在 GRUB 参数中添加 break=[break_point] 来触发。break_point 的取值包括以下几种:

  • top:initramfs 启动过程的最开始阶段。
  • modules:加载必要的内核模块阶段。
  • premount:挂载根文件系统之前的准备阶段。
  • mount:挂载根文件系统的阶段。
  • mountroot:挂载根文件系统的具体实现阶段。
  • bottom:initramfs 启动过程的最后阶段。

通过在特定阶段暂停启动过程,可以方便地检查和干预启动过程)。

我一般习惯先开最后,再看开头,翻到最后面,可以明显看到是 initramfs 阶段找不到对应的init进程(其实就是找不到系统的/),所以就单独启动了一个sh终端,方便使用者自行分析。

image

系统无法启动的原因已经找到,接下来就是查看为何找不到init进程,这需要我们找到最初开始报错的地方,查找起来实际还是很轻松的,如下图,果然是这里异常了,知道了问题我们在下次启动时,手动调整对应的grub参数即可解决.

image

分阶段调试

前面说了,initramfs 中存在很多maybe_break的天然断点,按照起前后执行顺序如下所示:

    1. top

作用:这是 initramfs 启动过程的最开始阶段。

调试用途:如果在启动参数中设置 break=top,系统会在 initramfs 的初始化脚本开始执行时暂停,方便用户检查早期启动环境。

    1. modules

作用:在这个阶段,系统会加载必要的内核模块。这些模块通常是根据 /conf/modules 文件的配置加载的,尽管在现代系统中,/conf/modules 文件可能不存在,因为很多模块已经通过 udev 动态加载。

调试用途:如果设置 break=modules,系统会在加载模块之前暂停,用户可以检查模块加载情况或干预模块加载过程。

    1. premount

作用:这个阶段是为了挂载根文件系统做准备。它会运行 /scripts/init-premount 目录下的脚本,这些脚本通常用于初始化设备和文件系统,例如启动 udev 守护进程、处理 USB 或 FireWire 设备等。

调试用途:如果设置 break=premount,系统会在挂载根文件系统之前暂停,用户可以检查设备初始化情况。

    1. mount

作用:这个阶段的主要任务是挂载根文件系统。它会执行 /scripts/local 中的 mountroot 函数,检测根文件系统的类型并将其挂载到 ${rootmnt}

调试用途:如果设置 break=mount,系统会在挂载根文件系统之前暂停,用户可以检查挂载参数或干预挂载过程。

    1. mountroot

作用:这个阶段是挂载根文件系统的具体实现阶段。它会根据启动参数(如 root=)解析根文件系统的设备路径,并尝试将其挂载到指定的挂载点。

调试用途:如果设置 break=mountroot,系统会在挂载根文件系统的过程中暂停,用户可以检查挂载失败的原因。

    1. bottom

作用:这是 initramfs 启动过程的最后阶段。在这个阶段,系统会执行 /scripts/init-bottom 目录下的脚本,这些脚本通常用于清理和完成启动过程中的最后一步操作。

调试用途:如果设置 break=bottom,系统会在启动过程的最后阶段暂停,用户可以检查启动过程中的最后一步操作。

通过在 grub 中添加break=[mount_point]可以让启动过程分别停止在不同的阶段,更方便我们确认是哪个环节出现了问题.

分析 initrd内容

当我们安装内核获驱动时,我们一般会执行 update-initramfs 命令,生成新的 initrd,偶尔也会出现生成的initrd内容异常的问题.我们可以对比 update-initramfs 前后的 initrd 内容.

initrd 存放于 /boot/initrd.img-* ,大小一般在200MB以内, 通过lsinitramfs命令查看其内容,通过对比更新前后的 initrd 可以发现绝大部分问题,

image

如果确实是update-initramfs命令执行后 initrd 内容出现了问题,也不要恐慌,update-initramfs 也只是一个普通的 bash 脚本而已,分析其源码实现即可,这也是我们了解系统启动过程的一个绝好机会.

image

卡死无输出,无日志,键鼠无反应

实话说,很少见,一般都出现在未适配的硬件上面,这种情况需要电脑有串口(电脑没有串口怎么办?凉拌),通过串口查询内核输出的日志,串口的使用网络上有很多资料,因为问题不太常见所以在碰到后您可以直接百度搜索如何配置串口参数,并联系专业的内核研发人员陪同定位.

写在最后

想到哪里就记到哪里了,后续再随时补充…

 Comments
Comment plugin failed to load
Loading comment plugin