跳转至

记一次 linux 系统无法启动修复过程

背景

我想要把第二张显卡也直通给虚拟机,然后就自己编译了一个打了 acs overide patch 的内核。之后启动也没有问题。但是当我第一次运行虚拟机后,电脑就卡死了。然后我强制关机后,无法进入系统,而进入了 busybox initramfs 交互命令行。提示文件系统错误,让我 fsck 系统盘。我照做后就成功进入系统了。

  • 这里进入系统后一切正常,但是 lxc 的 storage 显示 unavailable,zpool import zfs_lxd.img 显示损坏。

然后我想再试试,结果启动虚拟机后又卡死了。我强制重启后,好像又进入 busybox 进行 fsck 了,但结果还是进不了系统,这次进入了紧急模式。

过程

紧急,emergency 模式

主要的报错是FAT-fs IO charset iso8895-1 not found, 提示让我登录查看日志,我登录后 df -h,发现确实 efi 分区是没有挂载的。紧急模式下,其它命令好像都没啥问题,zsh 的配置都是我的 oh-my-zsh。

网上有一样的报错

但是他们提到的进入恢复模式,然后运行 depmod,我无法做到:

  • 我不知道怎么进入恢复模式,因为我重启就会进入这个紧急模式无限循环
    • 其实是因为我把 grub 设置为 hidden 并且延迟为 0,开启后就可以进入 grub 界面选择内核版本以及紧急模式
  • 在紧急模式中我无法 fsck 系统盘,因为已经挂载了(efi 分区可以,但是没有错误)
  • 紧急模式中无法运行 depmod 命令(这里其实已经反映问题了)

希望,livecd 修复

我以为是 efi 分区损坏了,在反复 fsck 无效后,我决定重建 efi 分区。于是通过 U 盘进入了 ubuntu20 的 livecd(22 版本启动很慢)

gparted格式化并重建分区

# 挂载efi分区和系统分区
mount /dev/nvmexxx   /xxx
mount /dev/nvmexxx   /xxx/boot/efi

cd /xxx
mount -t proc /proc proc
mount --rbind /sys sys
mount --rbind /dev dev

chroot /xxx

# 更新efi分区UUID(格式化后改变)
vim /etc/fstab

update-grub
grub-install

发现在 chroot 系统里也无法运行depmod, modeprobe等命令,提示我安装zmod,但是安装时又告诉我已经安装了。(这里又再次反映了问题所在)

重建 efi 分区后依然还是卡在紧急模式。

尝试,grub recovery 模式

修改 grub 配置后,可以进入 grub 菜单了。 我尝试 grub 选择旧的内核的 recovery 模式,但是却很不稳定,几乎立刻又会进入紧急模式,导致无法运行文字菜单中。

解决,kmod 不翼而飞

和 czw 讨论,复盘了下整个过程,并终于发现问题所在:

无法挂载 efi 分区 <- iso8895 错误 <- nls_iso8895-1.ko 不存在 <- find /lib/module/自己编译的内核/,发现ko文件是存在的。 modprobe 命令无法运行 <- 发现 modprobe 是一个链接指向/bin/kmod,并且是红色的,表示链接是无效的。 <- 发现/bin/kmod 文件不存在!

于是从 czw 的机器上拷贝了一份 kmod 文件,结果恢复模式可以进入了,机器也可以正常启动。

  • p.s 发现 lxc zfs pool 又损坏了

总结

linux 启动过程

Arch boot process - ArchWiki (archlinux.org) Understanding the Boot process — BIOS vs UEFI (linuxhint.com)

OS 启动过程:

  • 固件:CPU 最开始执行的指令。主要工作 POST 自检,硬件初始化,加载引导程序
  • 引导程序:加载 os 内核(可以指定内核参数、初始文件系统)
  • 内核:
    • 初始化,如硬件初始化,驱动加载
    • init:用户空间初始化。1-6 不同 run level,如 level 1 为 single user,level 3 为多用户命令行,level 5 包含图形化界面
      • p.s level 6 为 reboot

BIOS

  • BIOS,位于主板 flash
  • 一级引导程序,位于 MBR,几百字节,非常小,用于加载二级引导程序
  • 二级引导程序(grub),位于
  • 内核,linux 内核 (vmlinuz) 位于系统盘/boot 路径下,有不同版本。该路径同时还有初始文件系统 (initrd.img)

UEFI

  • UEFI,位于主板 flash
  • EFI 应用(grub),位于 ESP 分区(通常为 FAT32 文件系统)。grub image 在/boot/grub

    root@Ryzen-Ubuntu22 ➜  yfy ls /boot/efi/EFI/ubuntu
    BOOTX64.CSV  grub.cfg  grubx64.efi  mmx64.efi  shimx64.efi
    root@Ryzen-Ubuntu22 ➜  yfy ls /boot/efi/EFI/BOOT
    BOOTX64.EFI  fbx64.efi  mmx64.efi
    

各种救援模式

grub rescue

  • 内核还没加载前,gurb 错误。如无法读取配置文件,需要手动指定 kernel 位置(哪个磁盘,哪个分区)
  • grub 其它:
    • 按 ESC 进入命令行模式,输入 normal 重回菜单界面。
    • 菜单界面输入 e,可以编辑启动项。
    • 选择 Ubuntu Advance,可以选择不同 kernel 版本,或者进入 recovery 模式

recovery 模式

  • 将以单用户模式 (single-user) 模式启动,是最低的 runlevel。
  • 用途:
    • 忘记 root 密码
    • 其它模式可能无法进入系统,而可以进入 recovery 模式进行恢复,或者备份文件。
  • 后面要介绍的两个模式,则是系统无法挂载,被迫进入的模式。

Busybox Initramfs

  • 内核初始化过程中,检测到根文件系统损坏。(initramfs 在内核初始化到能够挂载根文件系统前使用,busybox 包含常用的命令)
  • 通常 fsck 文件系统即可

emergency 模式

  • 内核初始化过程中因为一些原因崩溃
  • 以只读模式挂载文件系统

心得

  • 折腾之前做好最坏的打算。比如这次在我进入不了系统后,我最坏的情况是将重要文件、配置拷贝出来,然后重新安装系统。期间我可以使用我的笔记本干活(因为我的 workspace 文件夹是搭建了自动同步的)。如果在我的系统崩掉期间,我啥都干不了,那我的心理压力是会非常大的。