记一次 Linux 系统引导修复与优化

前言

这几天把后端的一些组件升级了下,发了 JKit 的第一个 Beta 版本,为小工具集的下一代 API 做好准备,有了些空闲时间,想着折腾一下自己干活用的设备。

我日用的电脑是 Linux 系统,这几天在关注一个启动管理器 systemd-boot,对 Linux 有一些了解的小伙伴们知道,目前 Linux 上最常用的启动管理器是 GRUB,这玩意是很早之前的产物了,比较臃肿,所以决定把它换掉,优化下启动速度。

我的系统环境如下:

  • 操作系统:Manjaro Linux
  • 内核:Linux 6.13.0-rc7-1-MANJARO
  • CPU:AMD Ryzen 7 8845H
  • 文件系统:Btrfs(使用了 Sub Volumes)
  • systemd 版本:257
  • GRUB 版本:2.12-3

折腾

Manjaro 基于 Arch Linux,内置了完整的 systemd 组件,所以直接按照 Arch Wiki 相关页面的说明 把 systemd-boot 安装到 EFI 分区:

bootctl install

然后在 /boot/efi 下创建 loader 目录,在 loader 里面再创建 entries 目录,把两个配置文件填好,保存,重启。

systemd-boot 成功加载了,但没有显示我的启动项,好在之前使用 GRUB 创建的启动项还没有从 EFI 删掉,选择之前的启动项进入系统,开始排查原因。

找了一些资料,问了 AI,排查了命名、文件权限等问题,最后运行 bootctl 发现我配置的镜像文件目录不对,所以 systemd-boot 将配置文件视为无效忽略了,用 cp 命令把文件复制到正确的目录,再调整一下配置文件就可以解决这个问题。

需要复制的两个文件分别是:

  • initramfs-6.13-x86_64.img:系统引导前在内存中加载的精简环境
  • vmlinuz-6.13-x86_64:Linux 内核本身

这两个文件由 mkinitcpio 生成,默认输出路径是 /boot,GRUB 也是从这个目录加载启动文件的,但对于现代的 UEFI 系统,systemd-boot 需要从 /boot/efi 目录寻找启动文件,且这个目录是单独的分区,和 /boot 彼此不互通。

除了复制以外,还可以修改 /etc/mkinitcpio.d/ 目录下每个内核的 Preset 文件,调整输出目录解决这个问题,这里我只修改了 Linux 6.13 内核的输出目录,6.6 内核平时并不使用,仅在系统出现问题时用作后备。

生成新的内核文件:

mkinitcpio -P

再次重启,这次可以识别启动项了,但尝试启动时出现了如下报错:

ERROR: Root device mounted successfully, but /sbin/init does not exist.

在 Linux 中,所有用户态进程都 fork 自 init 进程,这里系统完成了内核部分的初始化,但在引导进入用户态的过程中出现了问题。

进行了相当长时间的排查后,排除了配置问题、文件路径问题、文件权限问题,最后死马当活马医,尝试删除 GRUB 相关依赖来排除潜在的冲突:

pacman -Rsn grub os-prober grub-btrfs grub-theme-manjaro install-grub update-grub
rm /boot/efi/EFI/grub

重启,这下彻底完蛋了:原先由 GRUB 创建的启动项依赖于 GRUB 本身的组件,于是直接报错缺失组件,启动失败。

至此第一部分结束,我成功把本来能用的系统搞坏了。

修复

Linux 玩家一般手边都会有一个 Live CD U 盘,类似于 Windows 的 PE 环境,但是更全面,理论上你可以在 Live CD 环境中体验完整的系统功能,只不过对系统的修改不会被保存下来,有点类似 Windows To Go。

之前因为系统更新时按了 Ctrl + C 强制中断,碰巧那个更新又涉及内核升级,GRUB 引导配置没有同步更新,系统启动失败,进 Live CD 环境更新配置就解决了。

我每月都会从 Manjaro 官网下载最新的系统镜像更新到 Ventoy 启动盘里,于是不慌不忙的插入 U 盘,选择启动项,然后...报错了:

grep: /init: No such file or directory
grep: init: No such file or directory

 ############ INIT NOT FOUND ############

所以为什么对硬盘上引导的修改还会导致 Live CD 启动失败呢?暂时不管那么多,在 Manjaro Live CD 启动界面选择使用 GRUB 2 启动,这次成功了。

(后来发现这个报错和我折腾的过程无关,单纯是因为下载的镜像本身存在问题)

我们要做的事情很简单:去它的 systemd-boot,我不折腾了,把 GRUB 装回来。

Live CD 环境有完整的驱动,所以先联网,后面下载驱动要用。

打开终端,切换到 Root 身份,不然下面的命令要频繁地加 sudo,会很麻烦:

su

Manjaro Live CD 的用户密码是 manjaro

首先要挂载系统硬盘上的分区,查看分区列表:

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE
nvme0n1     259:0    0 953.9G  0 disk
├─nvme0n1p1 259:1    0   300M  0 part
├─nvme0n1p2 259:2    0   256G  0 part
└─nvme0n1p3 259:3    0 697.6G  0 part

挂载分区的命令是 mount,硬盘的块设备在 /dev 目录,前面 lsblk 输出中的第二个分区是根目录分区(第一个是 EFI 分区),一般挂载到 /mnt 目录下,所以很显然命令是:

mount /dev/nvme0n1p1 /mnt

是...吗?对于 ext4 文件系统来说是的,但对于使用了 Sub Volumes 的 Btrfs 文件系统,我们还需要通过 -o 指定需要挂载的子卷,这里我们要挂载 @,也就是根目录对应的子卷,所以应该使用:

mount -o subvol=@ /dev/nvme0n1p2 /mnt

如果不知道有哪些可用的子卷,可以先不添加参数挂载,然后 ls /mnt,显示的文件夹就对应着子卷的名称,然后 umount /mnt 取消挂载。

接下来,我们把 EFI 分区挂载到 /boot/efi 目录,注意是硬盘上的目录,我们把硬盘的根分区挂载到了 /mnt,所以命令是:

mount /dev/nvme0n1p1 /mnt/boot/efi

执行 ls /mnt/boot/efi,已经可以看到 EFI 分区中对应的文件了。

nvme0n1p2 这个 Btrfs 分区中还有两个子卷 @cache@log,分别对应系统缓存和日志的目录,修复过程中不会用到它们,所以不需要挂载。

如果不确定分区的挂载点,可以查看硬盘上系统的 fstab 文件:

cat /mnt/etc/fstab

接下来我们需要“进入”系统完成修复,用到的工具是 chroot,具体来说,是 Manjaro 提供给我们的 manjaro-chroot

原版 chroot 我使用时存在安装软件包时提示网络错误的问题,与本次修复无关,不做深究。

总之:

manjaro-chroot /mnt

命令提示符变化,说明我们成功进入了硬盘上的系统。

接下来用 Live CD 中的 Firefox 浏览器打开 Arch Wiki GRUB 页面,参考其中的命令:

先把 GRUB 安装回来:

pacman -S grub install-grub update-grub

这里我没有把之前删掉的 GRUB 组件都安装上,这些组件足以完成修复让系统正常启动,如果不放心可以查找 Shell 命令历史记录,对照着把所有软件包都安装回去。

我之前修改过 mkinitcpio 的镜像生成路径,这里要先改回去,然后重新生成所有镜像文件:

mkinitcpio -P

我的系统使用 UEFI 启动,所以执行这条命令,把 GRUB 安装到 EFI 分区:

grub-install --target=x86_64-efi --efi-directory=esp --bootloader-id=GRUB

此时 /etc/default/grub 目录下的 GRUB 配置文件已经自动创建完成,可以直接重建 GRUB 启动项:

update-grub

搞定,退出 chroot 环境,解除所有分区的挂载,重启系统:

exit
umount /mnt/boot/efi
umount /mnt
reboot

过程略显复杂,我搞了大概半小时,终于看到了熟悉的系统桌面。

优化

首先,把本次事件的罪魁祸首 systemd-boot 删掉:

bootctl remove

GRUB 配置文件恢复到了默认值,需要做一些调整,首先把内核参数调回来:

nvim /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet nowatchdog mitigations=off"
  • nowatchdog 可以略微降低功耗,同时避免关机时关于 Watchdog 的报错,建议加上。
  • mitigations=off 会禁用系统对 CPU 漏洞的缓解措施,有一定安全风险,但可以小幅提升性能,这一点见仁见智。

GRUB_TIMEOUT 设置为 0,可以跳过启动项选择界面,加快开机速度。需要切换内核 / 修改启动参数时,可以在启动时按住 Esc 键调出 GRUB 菜单。

注释掉 GRUB_DEFAULTGRUB_SAVEDEFAULT,可以避免使用 Btrfs 作为根分区的系统在启动时出现 error: sparse file not allowed 报错,不过这个报错并不影响正常启动。

由于我的硬盘使用 GPT 分区表,所以只需要 part_gpt 一个模块:

GRUB_PRELOAD_MODULES="part_gpt"

至此 GRUB 相关的优化结束,记得更新引导配置:

update-grub

接下来找到 mkinitcpio 的配置文件 /etc/mkinitcpio.conf

参考 Arch Wiki mkinitcpio 页面 3.3.2 节的 Common hooks 表格调整 HOOKS 配置项:

HOOKS=(systemd autodetect microcode kms modconf block keyboard filesystems)

这里我使用 systemd 替换了 udevusr 两个 Hooks,让 systemd 提早启动,从而更早开始服务加载,提升启动速度。

由于已经有了 filesystems 模块,所以 btrfs 模块在我的系统中也不是必需的,可以删去。

然后是 /etc/mkinitcpio.d/ 目录下每个 Linux 内核的配置文件,以 Linux 6.13 为例:

ALL_kver="/boot/vmlinuz-6.13-x86_64"

PRESETS=('default')

default_image="/boot/initramfs-6.13-x86_64.img"

这里只构建了 default initramfs,fallback 包含更完整的驱动和内核模块,用于在遇到兼容性问题时正常启动,我有 Linux 6.6 LTS 和最新测试版两个内核,加上 Live CD 足以满足排错需求,不构建 fallback 可以加快系统升级时构建 initramfs 的速度,也能让 /boot 目录更精简。

完成之后重新生成 initramfs:

mkinitcpio -P

重启系统,查看启动耗时:

systemd-analyze
Startup finished in 6.125s (firmware) + 474ms (loader) + 623ms (kernel) + 2.459s (initrd) + 2.102s (userspace) = 11.787s
graphical.target reached after 2.102s in userspace.

实测从按下开机键到进入桌面耗时 18s,相比之前的 30s+ 有明显缩短,且开机过程中不再出现报错信息。

总结

又是依次从折腾到踩坑,再凭借自己努力爬出来,绕过去,顺便把烂摊子收拾一下的过程。

Linux 用户有很多都喜欢折腾自己的系统,在一次次出问题到解决问题的过程中成长,了解一个先进的操作系统,包括计算机本身的运作原理。我自己也是计算机专业,后面会有 Linux 操作系统的课程,也算是小小预习了一下。

总结出几条经验:

  • 修改重要组件时,确认新组件完全正常正常工作前不要删旧的
  • Live CD 文件不仅要定期更新,还要比对校验和以及做测试确保能正常启动
  • Arch Wiki 是个好东西,不管你用的是什么 Linux 发行版
  • 一定不要在 早晨和晚上 有工作安排的时候折腾自己干活的设备
  • 备份,说再多遍也不为过

希望对同样使用 Linux 系统的小伙伴们有所帮助。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容