周六早上我远程连家里那台Linux NAS,结果怎么都ping不通。过了一会儿家人拍来一张照片,屏幕停在黑底白字的启动界面,上面明晃晃一行字:“Welcome to emergency mode!”看到这行字我反而松了口气,因为这类故障我处理过太多次了。Linux系统卡在启动界面进不去、直接掉进紧急模式,十次里有八九次是/etc/fstab里面的UUID和硬盘实际的UUID对不上,系统在引导阶段找不到要挂载的分区,干脆降级把控制权交回给用户。这台机器的数据盘前阵子刚重新分过区,我猜多半是fstab里还残留着旧分区的UUID。输入root密码登录,查日志一看,果不其然——挂载失败的分区正是那会儿动过的盘。
这篇文章适合谁看?自己折腾Linux桌面或服务器的,买了一台二手服务器准备装NAS的,搞嵌入式开发经常要改启动配置的,都应该把这篇存下来。不需要你多熟悉systemd,只要会敲命令能看懂路径,照着下面的排查链路一步步走,大概率能自己把系统救回来。
1. 紧急模式不是系统崩了,是systemd在跟你对暗号
很多人第一次看到emergency mode那几行字就慌了,以为硬盘坏了、系统报废了。其实不是。我可以负责任地告诉你,绝大多数emergency mode都是挂载配置问题,不是硬件物理损坏。系统给出的提示原文一般是这样的:
Welcome to emergency mode! After logging in, type "journalctl -xb" to view system logs, "systemctl reboot" to reboot, "systemctl default" or ^D to try again to boot into default mode. Cannot open access to console, the root account is locked.最后那句话不同发行版不一样,有的会提示root被锁,有的直接让你输root密码。不管哪种,你先要知道emergency mode到底是怎么触发的。
Linux系统(尤其是用了systemd的发行版,比如CentOS 7+、Ubuntu 16.04+、Debian 8+)在开机引导阶段会按照/etc/fstab文件一条条去挂载分区。fstab的全称是File System Table,相当于一份“分区挂载清单”。systemd在启动时会根据这份清单生成对应的挂载单元,如果某个挂载项失败了,比如设备不存在、UUID对不上、文件系统损坏,systemd的依赖关系就会断掉。因为默认的local-fs.target是要等所有fstab里的分区都挂载成功才算完成,一旦中间断了,系统就进不了multi-user.target或者graphical.target,最终被降到最底层的emergency.target。
这里要区分两个概念:rescue.target和emergency.target。很多教程混着说,实际上不一样。
- rescue.target(救援模式):会尝试把本地文件系统都挂载好,然后给你一个root的shell,适合修复系统配置。
- emergency.target(紧急模式):更底层,它只挂载根文件系统(而且通常是只读的),其他分区一概不管,是systemd能给你的最小运行环境。
大多数发行版在fstab挂载失败后会落到emergency.target,所以你在“紧急模式”里看不到自己的数据盘,这是正常的,不是数据丢了。如果启动时没看到emergency mode提示,而是卡在黑屏或者直接停在“Reached target Local File Systems (Pre)”之类的状态,那就是挂载单元超时或者死锁,后面我们单独说。
另外一个特别常见的误判是:以为emergency mode是硬盘坏了所以找不到设备。实际上很多时候设备在系统里活得好好的,只是fstab里写的UUID是旧的,或者fstab里写的是/dev/sdb1这种设备路径,而内核这次枚举出来的盘符变成了/dev/sdc1。同一个物理分区,三个字段/dev/sdb1、/dev/disk/by-uuid/xxxx、UUID=xxxx指向的可能都是它,但只有UUID是永久的,设备路径会变。这就是为什么现代发行版默认都用UUID而不是设备路径挂载硬盘——盘符的顺序本身就不稳定,尤其在挂了多块硬盘、或者BIOS里存储设备探测顺序有变化的时候,/dev/sda可能第二天就变成/dev/sdb,如果fstab里写的是设备路径,开机基本上就是赌博。
我把常见触发场景整理成了表格,你可以先对号入座:
| 触发场景 | 典型表现 | 根因 |
|---|---|---|
| fstab里UUID写错或残留旧UUID | 报错提示找不到设备,blkid能看到盘 | 分区后没有同步更新fstab |
| 用dd/Clonezilla/再生龙克隆过系统盘 | 新机器报一堆挂载失败 | 克隆盘继承了旧分区的UUID |
| 换过主板、改动过BIOS启动顺序 | 盘符顺序变了 | fstab用了设备路径而不是UUID |
| 拔掉了某块数据盘/备份盘 | 开机进emergency mode | fstab还挂着那块盘,没加nofail参数 |
| swap分区UUID不对 | 挂载swap失败 | 格式化过swap分区,UUID变了 |
| 文件系统损坏 | 卡在fsck界面或提示Dependency failed | 需要手动修复文件系统 |
2. 一步步揪出元凶:从journalctl到blkid的完整排查路径
进了紧急模式以后,别急着瞎改东西,也别急着重启。按我下面的顺序来,基本两分钟就能定位问题。
第一步:把根文件系统重新挂载为可写
紧急模式下根文件系统默认是只读的(ro),因为systemd为了保证最小环境的稳定,不开任何不必要的东西。你如果直接打开fstab想改,保存的时候会提示“Read-only file system”,改了个寂寞。所以进来第一件事,执行:
mount -o remount,rw /再确认一下:
mount | grep " / "看到根分区挂载方式带rw就说明可以写入了。这条命令建议养成肌肉记忆,不管是emergency mode还是rescue mode,第一步永远是它。
第二步:查看启动日志,找到挂载失败的元凶
紧急模式界面里明确提示了用journalctl -xb查看日志。这条命令的意思是:-x显示辅助说明(会附带一些SVN代码含义解释),-b表示显示本次启动(boot)的日志。执行:
journalctl -xb日志一般很长,一屏根本看不完,你需要用方向键或者PageUp/PageDown翻页,按q退出。我习惯的做法是配合grep过滤,直接找失败相关的关键词:
journalctl -xb | grep -i "fail\|error\|mount"也可以把错误信息直接保存成文件再慢慢看:
journalctl -xb > /tmp/boot.log grep -i "fail" /tmp/boot.log日志里你会看到类似这样的关键片段:
Feb 12 08:12:33 nas systemd[1]: Mounting /mnt/data... Feb 12 08:12:34 nas systemd[1]: mount: /mnt/data: new mount failed: No such device or address. Feb 12 08:12:34 nas systemd[1]: Failed to mount /mnt/data. Feb 12 08:12:34 nas systemd[1]: Dependency failed for Local File Systems.看到“No such device or address”,基本就实锤了:fstab里写的设备和系统实际看到的设备对不上。这时不要着急去翻fstab猜,直接把系统里真实的UUID列出来。
第三步:用blkid列出当前系统实际的分区UUID
blkidblkid会列出当前系统能识别到的所有块设备和它们的UUID、文件系统类型等。举个例子,输出长这样:
/dev/sda1: UUID="2b6d4b36-8c7f-4b4f-9a02-5f5d9e6f3e2a" BLOCK_SIZE="4096" TYPE="xfs" PARTUUID="d0f0c5f2-01" /dev/sda2: UUID="a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d" TYPE="swap" PARTUUID="d0f0c5f2-02" /dev/sdb1: UUID="c9d8e7f6-5a4b-3c2d-1e0f-abcdefabcdef" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="a1b2c3d4-05"然后把这份输出和fstab里的记录做对比。fstab在/etc/fstab,直接查看:
cat /etc/fstab正常情况下你会看到类似这些行:
# /etc/fstab # <file system> <mount point> <type> <options> <dump> <pass> UUID=2b6d4b36-8c7f-4b4f-9a02-5f5d9e6f3e2a / xfs defaults 0 1 UUID=a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d swap swap defaults 0 0如果fstab里的某个UUID在blkid的输出里完全找不到,那这个分区就是孤儿了。要么盘被拔掉了,要么分区被重建过、UUID变了。如果blkid里有一个UUID和fstab里写的长得不一样但分区内容明显是同一个盘,那就是分区格式化或重建导致UUID变了,fstab没跟着更新。
第四步:判断是哪个挂载点失败
如果journalctl输出太杂,还有一个更直接的方法:在紧急模式下逐条手动挂载fstab里的所有分区,哪条报错哪条就是病根。可以用下面这样的循环命令(注意如果某一行是特殊选项需要手动看情况):
mount -amount -a表示挂载fstab中所有未挂载的文件系统。它会按fstab顺序尝试,哪一行出错,它会直接打印哪一行对应的错误。比如:
mount: /mnt/data: mount point does not exist.这又是另一种常见问题:fstab里指定的挂载点目录不存在。别忘了挂载点本身要提前建好。这种情况新建目录就行:
mkdir -p /mnt/data3. 修改UUID挂载:改fstab的正确姿势和背后逻辑
定位到具体是哪一行出了问题,接下来就是修复。修fstab不是拿个文本编辑器改了UUID就完事,有几个操作细节和验证步骤能帮你少走弯路。
3.1 动手前先备份
这条真是老生常谈,但每次都会有人省略。我见过不少人在紧急模式里手一抖,多删一行,系统重启后连emergency mode都进不去了,只能拿Live CD去救。改任何系统配置文件,第一件事永远是备份:
cp /etc/fstab /etc/fstab.bak.$(date +%Y%m%d%H%M)备份文件放当前目录就行,它跟fstab待在同一个分区里。万一改坏了,系统启动到单用户模式或者用安装盘挂载根分区,把备份复制回来就能恢复。注意备份文件名不要带中文、不要带空格,越简单越好。
3.2 修改fstab中的UUID
在紧急模式下,vi/vim的用法和平时一样。打开文件:
vi /etc/fstab找到那个对不上的UUID行,把旧的UUID替换成blkid输出里正确的UUID。这里有个易错点:复制UUID的时候不要带引号,也不要带前后空格。比如:
UUID=c9d8e7f6-5a4b-3c2d-1e0f-abcdefabcdef /mnt/data ext4 defaults 0 2如果你的分区之前是swap分区,那行应该长这样:
UUID=b1c2d3e4-5f6a-7b8c-9d0e-1f2a3b4c5d6e none swap sw 0 0顺便把fstab的六列字段含义给你整理一下,看不懂的行对着查:
| 列 | 含义 | 例子 |
|---|---|---|
| 第1列 | 设备标识:UUID或设备路径 | UUID=xxxx或/dev/sda1 |
| 第2列 | 挂载点(swap分区写none) | /boot、/home、none |
| 第3列 | 文件系统类型 | ext4、xfs、swap、ntfs |
| 第4列 | 挂载选项 | defaults、noatime、nofail |
| 第5列 | 是否用dump备份,0为不备份 | 0 |
| 第6列 | fsck检查顺序:根分区1,其他2,swap/光驱0 | 1 |
3.3 改完先别重启,用mount -a验证
这是最关键的一步。很多人改完fstab直接reboot,结果改错了又进一次紧急模式,来回折腾。正确姿势是改完后先用命令验证:
mount -a这条命令会尝试挂载所有fstab里配置的文件系统。如果执行后没有任何输出、也没有报错,说明这一版fstab在语法和设备匹配上基本没问题,你再执行:
systemctl daemon-reload reboot如果你改了好几个挂载点,想单独验证某一个,也可以直接手动mount那个分区:
mount /mnt/data注意mount这里不带设备参数也行的前提是fstab里有对应挂载点的配置,它会自动去fstab里找。
3.4 如果报错是“wrong fs type”或者“mount point does not exist”
这两个报错和UUID无关,但同样害人。
mount: /mnt/data: wrong fs type:fstab第3列写的文件系统类型和分区实际格式对不上。比如分区实际是ext4,你写了xfs。用blkid能看到真实的TYPE,改回来即可。mount point does not exist:挂载点目录不存在。用mkdir -p /mnt/data建目录即可。注意fstab里写的是多级路径要先确保父目录都存在。
4. 比UUID更值得关注的三种特殊场景:swap、克隆盘、可插拔盘
上面那套流程能解决绝大多数fstab相关的emergency mode,但有三类特殊场景,光改UUID还不够,得单独处理。
4.1 swap分区失败:swapon和fstab的双重检查
swap分区(交换分区)写错UUID同样会触发emergency mode。但它的表现和普通数据盘不太一样。实际报错可能是:
Feb 12 08:12:33 nas systemd[1]: Reached target Swap.或者干脆卡在swap挂载上。如果你用blkid发现swap分区还在,但fstab里的UUID是旧的,直接改;如果blkid里压根没有type="swap"的行了,说明这个swap分区被删除或者格式化成别的文件系统了。这时候两个选择:要么把swap那行从fstab里删掉,要么重新建一个swap分区(用mkswap,注意会清空分区数据)。
另一个常见误区:swap分区那行的挂载点要写none,类型写swap,选项写sw,别写默认的defaults。某些发行版对defaults的swap也能识别,但严格按规范来最稳妥。
4.2 克隆盘/镜像还原后的UUID冲突:不只是fstab的问题
用dd、Clonezilla、再生龙这类工具把系统盘整体克隆到新硬盘,或者从模板虚拟机导出镜像,目标机开机后大概率会出现emergency mode。原因是克隆出来的盘和源盘UUID一模一样,但你原来的环境里可能还同时插着源盘,两个分区UUID冲突,或者目标机的块设备命名变了。
这时候很多人只改fstab,改了重启还是报错——因为还有另一个地方藏着旧UUID:GRUB引导配置文件。有些发行版(比如CentOS/RHEL系列)在/etc/default/grub或者生成好的/boot/grub2/grub.cfg里会写死root=UUID=xxxx这样的内核引导参数。如果这个UUID对不上,内核连根分区都挂不上,系统进度可能连emergency mode都到不了,直接卡在更早的阶段。
排查方法是执行:
cat /proc/cmdline这个文件记录的是内核本次启动实际接收到的引导参数。如果里面显示root=UUID=旧UUID,而blkid显示根分区已经是新UUID,你就需要更新GRUB配置:
grub2-mkconfig -o /boot/grub2/grub.cfg # 或者Debian/Ubuntu系: # update-grub注意:这一步可能需要chroot或者正常系统环境下执行,如果你人已经在emergency mode且根分区能只读挂载上,可以先把fstab修好,然后用grub2-mkconfig重新生成引导配置。最稳的是用Live CD启动,chroot进系统,再执行引导修复,但那是另一个话题,这里不展开。
4.3 给可插拔设备加nofail:把“可选盘”从启动依赖里摘出来
这是我最想强调的一件事:如果你fstab里挂了外接移动硬盘、USB存储、或者不是每次开机都一定在的备份盘,请在挂载选项那一列加上nofail。比如:
UUID=xxxx-xxxx /mnt/backup exfat defaults,nofail,x-systemd.device-timeout=10 0 2nofail的意思就是告诉systemd:这块盘挂不上也没关系,不要因为它失败就阻塞系统启动。这个参数能救你于水火。我见过不止一个人,因为一块平时插着的移动硬盘偶尔没插,导致整台服务器进不了系统,只能远程失联后干瞪眼。
与之配套的参数还有x-systemd.device-timeout=10,意思是等待设备出现最多10秒,超时就放弃。默认情况下systemd对某些设备类型的等待时间可能长达90秒甚至更久,你会觉得系统“卡死”在启动界面,其实是在等一个永远不会出现的设备。加上这个超时参数,最多等多长时间你自己说了算。
注意:nofail是给非系统盘准备的。根分区、/boot、/home这种系统关键分区千万不要加nofail,否则系统遇到真正的磁盘故障时也照常启动,然后会因为缺少模块在半路出各种奇怪问题,把故障掩盖起来,反而更难排查。
5. 那些“看似UUID问题,其实不是”的启动卡死场景
处理过大量引导问题之后,你会发现emergency mode只是Linux启动故障里比较友好的那一种。还有几种情况,现象相似但根因完全不同,有时候会把人绕晕。
5.1 文件系统损坏:fsck会在启动时和你对话
如果分区确实还在、UUID也对得上,但文件系统内部有损坏(比如突然断电、强行关机),systemd的启动过程会触发fsck检查。这时候屏幕可能不会进emergency mode,而是卡在一段文字界面,提示你手动运行fsck:
/dev/sdb1 contains a file system with errors, check forced.这种情况下你要么输入root密码执行修复,要么在emergency mode里手动运行:
fsck /dev/sdb1注意:执行fsck前,要确保对应分区没有被挂载。如果它在fstab里,你正在emergency mode里,通常不会自动挂载,可以放心修。修完再重启。fsck修完以后,UUID不会变,不需要改动fstab。这个场景经常被误报成“fstab出问题”,白白折腾半天。
5.2 根分区挂载失败:连emergency mode都进不去的情况
前面说的所有修复,都建立在systemd还能把根分区挂上、让你进emergency mode的前提下。如果根分区自己的UUID在引导参数里就是错的,或者根分区所在设备根本没被内核识别,系统会卡在更早的阶段——initramfs阶段,可能直接给你一个dracut shell(CentOS/RHEL系)或者busybox shell(Ubuntu/Debian系):
dracut:/#这时候看到的是dracut提示符而不是emergency mode。说明内核没能从根设备上读取根文件系统,系统连systemd都还没跑起来。处理方式通常是:在dracut shell里检查实际可用的设备:
blkid把实际根分区的UUID记下来,然后重启用GRUB引导,按e编辑启动项,把root=UUID=旧值改成刚才查到的正确UUID,按Ctrl+X或F10引导进去后再重新生成grub配置。如果你对GRUB编辑不熟,建议用系统安装盘或Live USB引导,chroot进去修复,更加万无一失。
5.3 网络挂载(NFS/CIFS)导致的启动卡死:等设备等到天荒地老
如果你fstab里写了NFS或者SMB/CIFS网络共享的挂载项,比如家里NAS的共享目录,而系统启动时网络还没就绪,或者NAS没开机,systemd会因为网络挂载单元一直等待,表现为开机过程非常漫长,甚至像卡死。这种不一定会进emergency mode,因为systemd还在等超时。
解决方案就是在网络挂载项的选项里加:
_netdev,nofail,x-systemd.automount,x-systemd.device-timeout=30_netdev告诉systemd,这是一个网络设备,必须等网络就绪后再尝试挂载。x-systemd.automount是懒挂载模式,开机时不真正挂载,等有人访问挂载点时再触发挂载,可以大幅提升开机速度。这个方案适合那种“访问到了才需要通的”网络共享。
6. 应急处置时的几个实操心得
最后分享一些平时不容易从文档里学到的经验,都是我在真实环境里踩坑踩出来的。
关于root账户被锁的问题。有些发行版比如Ubuntu,默认root密码是随机的,锁定的状态,emergency mode里提示无法登录root。这种情况下如果你必须得进emergency mode,大多数时候需要在GRUB引导菜单里按e编辑启动项,在内核参数那一行末尾加上systemd.unit=rescue.target或者single,然后再引导,这样系统会以提权方式给你一个shell。这个操作比修fstab更偏底层,我建议大家在虚拟机里先练一遍。
journalctl日志里红字优先原则。用journalctl -xb | grep -i fail过滤到的内容可能很多,看的时候优先找包含Failed to mount、Dependency failed for这些关键字的行,它们会直接指向出问题的挂载单元。那些Failed to start之类的内容多数是挂载失败的连带反应,不用管。记住,找准主故障点,比把所有报错都修一遍重要得多。
把要改的行注释起来,而不是删掉。修改fstab时,拿不准的那行先用#注释掉,重启验证没问题后再清理。注释行不会参与挂载,但保留了原始记录,出了问题你还能看到原来写的是什么,对排查非常有用。
一个行为准则:不要总盯着“改一下试试”,要找到为什么UUID会变。如果你的机器没有任何磁盘变更操作,UUID突然对不上了,这时候要警惕是不是硬盘本身出了问题。我的习惯是先用smartctl -a /dev/sdb看看硬盘健康状态,确认没有硬件故障再改fstab。不然你今天把UUID改了,明天盘彻底不认了,数据就真的麻烦了。
我处理启动故障比较多的那阵子,家里那台服务器几乎每两个月就要进一次emergency mode。后来养成了习惯:凡是挂数据盘、备份盘、移动盘,一律在fstab里配好nofail;凡是动过分区表,改完立刻同步fstab和grub配置,绝不拖到重启那一刻;凡是克隆磁盘,先辈份新的系统开一次机再往生产环境里接。养成这几个习惯之后,紧急模式半年都见不到一次。可一旦真碰到了,这整套排查链路二十分钟内基本都能定位问题所在——先看journalctl里的Failed to mount,再用blkid对照实际UUID,改完用mount -a验证一把,最后reboot收工。整个过程不复杂,每一步都有明确的判断依据。你只要记住emergency mode不是死刑判决,它只是系统在用最朴素的方式告诉你:有个分区没挂上,来修一下。