1. 挂载基础概念:什么是挂载、文件系统与挂载点的关系、Linux启动流程中的挂载阶段
各位同学好,我是老张。今天咱们正式开始《启动挂载问题排查》的第一章。说实话,挂载这个概念,很多搞了两三年Linux的人,理解得还是模模糊糊的。出了问题就知道mount、umount,但真要排查启动时的挂载失败,往往一头雾水。
这一章,我带你把地基打牢。咱们不讲虚的,就讲三件事:挂载到底是什么、文件系统和挂载点怎么配对、以及Linux开机时挂载是怎么一步步发生的。
1.1 什么是挂载?
挂载,说白了就是把存储设备上的文件系统,接入到目录树的一个目录下。
你想想看,一块硬盘插到服务器上,它本身只是一堆0和1。操作系统怎么访问它?必须通过一个目录作为入口。这个入口,就叫挂载点。
核心定义:挂载(mount)是将一个文件系统附加到当前目录树中某个已存在目录的过程。这个目录就是挂载点。
举个例子:
# 查看当前挂载情况
mount | grep sda1
# 手动挂载一个分区到 /mnt/data
mount /dev/sda1 /mnt/data
# 卸载
umount /mnt/data
我在项目中遇到过好几次,有人以为挂载就是把设备“插上去”就行了。其实不是。设备插上后,你得告诉系统:这个设备上的文件系统,请挂到 /data 这个目录下。系统才知道怎么用。
1.2 文件系统与挂载点的关系
文件系统和挂载点,是一对多的关系。一个文件系统只能挂到一个挂载点,但一个挂载点可以先后挂不同的文件系统(后挂的会覆盖之前的)。
我习惯用一张表来理解它们的关系:
| 概念 | 本质 | 例子 |
|---|---|---|
| 文件系统 | 存储设备上的数据组织格式 | ext4、xfs、btrfs、ntfs |
| 挂载点 | 目录树中的一个目录 | /、/boot、/home、/var |
| 挂载操作 | 建立文件系统到目录的映射 | mount /dev/sdb1 /data |
这里有个关键点:挂载点必须是一个空目录,或者至少你不介意它原来的内容被隐藏。为什么?因为一旦挂载上去,原目录下的文件就暂时看不到了。直到卸载后才会恢复。
注意:千万不要把设备挂载到非空目录上,除非你清楚后果。我曾经帮一个同事排查过,他把新硬盘挂到了 /var/log 上,结果所有日志都写到了新分区,旧日志全被“遮住”了。排查了三天才发现。
1.3 Linux启动流程中的挂载阶段
Linux开机,挂载不是一次性完成的。它分了好几个阶段。我画了一张流程图,你看完就明白了。
嗯,这张图你得存下来。咱们后面的章节,几乎每一章都会回到这张图上来。
1.4 启动挂载的三个关键阶段详解
我把启动挂载拆成三个阶段来讲,这样你排查问题时思路更清晰。
第一阶段:initramfs 中的早期挂载
内核启动后,首先加载 initramfs(初始内存文件系统)。这个阶段的目标只有一个:找到并挂载真正的根文件系统。
initramfs 里包含了一些必要的驱动和工具。比如你的根分区在 NVMe 硬盘上,但内核本身没有 NVMe 驱动,那 initramfs 就得把这个驱动加载上。
我的经验:很多启动挂载失败,都是 initramfs 没生成对。比如你换了硬盘控制器,或者改了根分区类型,但忘了重新生成 initramfs。我建议每次修改了存储相关的内核参数或硬件配置后,都执行一下:
# CentOS/RHEL
dracut -f
# Ubuntu/Debian
update-initramfs -u
第二阶段:切换根(pivot_root)
initramfs 挂载好真正的根文件系统后,会执行 pivot_root 系统调用,把根从 initramfs 切换到真正的根分区。然后 initramfs 被卸载,系统进入真正的用户空间。
这个阶段非常脆弱。如果真正的根文件系统挂载失败,系统就会掉入 emergency shell。你会在屏幕上看到类似这样的提示:
Welcome to emergency mode! After logging in, type "journalctl -xb" to view system logs, "systemctl reboot" to reboot, "systemctl default" or "exit" to boot into default mode.
Give root password for maintenance
(or press Control-D to continue):
我在项目中遇到过好几次,都是因为根分区的 UUID 在 fstab 里写错了,导致 pivot_root 失败。排查方法很简单:在 emergency shell 里用 blkid 查看实际 UUID,然后对比 fstab。
第三阶段:systemd 按 fstab 挂载其他分区
根文件系统挂载成功后,systemd 作为 PID 1 启动。它会读取 /etc/fstab,按照里面的配置挂载所有其他文件系统。
fstab 的格式是这样的:
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=abc123 /boot ext4 defaults 0 2
UUID=def456 /home xfs defaults 0 2
/dev/sdc1 /data ext4 noatime 0 2
这里有个坑:挂载顺序。systemd 会根据 fstab 中的依赖关系自动排序,但如果你有嵌套的挂载点(比如先挂 /data,再挂 /data/logs),必须保证父挂载点先挂载成功。
我曾经踩过的坑:有一次我把 /var 和 /var/log 分别挂到了两个不同的分区,但 fstab 里 /var/log 写在了 /var 前面。结果 systemd 尝试挂载 /var/log 时,/var 还没挂上,直接报错。系统启动后 /var/log 是空的,所有日志都写不进去。排查了一整天才发现是顺序问题。
1.5 挂载相关的关键文件
做启动挂载排查,这几个文件你必须烂熟于心:
| 文件/目录 | 作用 | 排查时关注什么 |
|---|---|---|
| /etc/fstab | 文件系统挂载配置表 | UUID、挂载点、选项、顺序 |
| /etc/mtab | 当前已挂载的文件系统列表 | 实际挂载状态(通常是 /proc/mounts 的符号链接) |
| /proc/mounts | 内核视角的挂载信息 | 最真实、最可靠的挂载状态 |
| /etc/default/grub | GRUB 引导配置 | root= 参数是否正确指向根分区 |
| /boot/grub2/grub.cfg | GRUB 实际使用的配置文件 | 内核启动参数是否包含正确的根设备 |
我个人的排查习惯:遇到启动挂载问题,第一步永远是看 /proc/mounts。它比 mount 命令的输出更底层、更准确。第二步看 fstab,对比实际挂载和期望挂载的差异。第三步看 dmesg 或 journalctl,找文件系统相关的错误信息。
1.6 本章小结
这一章咱们把挂载的底子打好了。你记住三句话:
- 挂载就是给文件系统找个目录入口
- 启动挂载分三个阶段:initramfs 挂根 → pivot_root 切换 → systemd 挂其他
- 排查挂载问题,先看 /proc/mounts,再看 /etc/fstab,最后看日志