一块新盘插进机器,lsblk里能看到它,df -h里却没有它,这个瞬间几乎每个碰过服务器的人都遇到过。MBR/GPT 磁盘分区、格式化、挂载这三件事,熟练的人三条命令收工,不熟的人能在fstab上折腾一整晚甚至把机器搞到起不来。它属于那种"看起来是入门操作、实际上处处有坑"的典型场景:分区表类型选错,超过 2TiB 的空间直接浪费;分区起点没对齐,SSD 的写入性能掉一半;fstab里写了个设备名而不是 UUID,换块盘顺序就全乱。这篇内容适合三类人看:刚接手服务器需要给数据盘做初始化的新手、写自动化脚本要批量处理几百块盘的运维、以及在自己机器上加硬盘但不想踩坑的爱好者。下面我按自己的实际动手顺序,把选型判断、分区工具、格式化参数、挂载持久化和故障排查这几块拆开讲,参数怎么算、坑长什么样、出了问题怎么救,都写清楚。
1. 先把 MBR 和 GPT 的账算清楚
1.1 分区表是磁盘的第一张户口本
分区表的作用很简单:它告诉操作系统"这块盘被切成了几段,每段从哪个扇区开始、到哪个扇区结束、是什么类型"。没有它,磁盘就是一整块连续空间,系统不知道该在哪里放文件系统。传统 MBR(Master Boot Record)把这张户口本塞在磁盘最开始的 512 字节里,结构非常紧凑:前 446 字节留给引导代码,紧接着 64 字节是 4 个分区表项,每项 16 字节,最后 2 字节是固定的0x55AA结束标志。16 字节要装下分区状态、分区类型、起始 CHS、结束 CHS、起始 LBA、扇区数量这么多信息,空间紧得不能再紧,这也直接决定了 MBR 后面所有的局限性。
GPT(GUID Partition Table)走的是另一条路。它在磁盘开头保留一个保护性 MBR(防止老工具误判为空盘),然后在 LBA1 放主 GPT 头,LBA2 到 LBA33 放 128 个分区表项,每个表项 128 字节,用 128 位 GUID 标识分区类型和分区本身。磁盘末尾还有一个完整的备份头和备份分区表。也就是说 GPT 从一开始就是按"分区可以很多、可以很大、还要能校验"这个思路设计的,和 MBR 那种 1980 年代挤出来的结构完全不是一个量级。
理解这个物理布局很关键,因为它解释了两件事:一是为什么 MBR 盘最多 4 个主分区,二是为什么 GPT 盘的分区表损坏后还有机会从备份恢复。后面讲排查的时候会用到这个知识点。
1.2 容量、分区数量、校验机制的三重差异
把两者的硬指标摆在一起,选型判断就非常直观了。
| 对比项 | MBR | GPT |
|---|---|---|
| 最大可寻址容量 | 2TiB(2^32 × 512B) | 约 9.4ZB(2^64 LBA,实际受系统限制) |
| 主分区数量 | 4 个,超出需扩展分区+逻辑分区 | 默认 128 个,可扩展 |
| 分区标识 | 1 字节类型码 | 16 字节 GUID |
| 完整性校验 | 无 | 头部和分区表均有 CRC32 |
| 备份机制 | 无 | 磁盘末尾保留完整备份 |
| 引导方式 | BIOS + 引导代码 | UEFI 原生,BIOS+GRUB 也可 |
| 分区名 | 不支持 | 支持 UTF-16 名称标签 |
容量这一项是最容易踩的。2TiB 的上限来自 32 位 LBA 乘以 512 字节扇区,这个数字在十年前还算宽裕,现在一块 4TB 的家用盘就顶穿了。我见过有人拿 4TB 盘做 MBR,分区工具只认到 2TiB,剩下 1.8TB 凭空消失,还以为是盘坏了。更隐蔽的情况是 2TiB 边界刚好卡在某个分区中间,写数据写到边界附近就开始报 I/O 错误,排查起来极其费劲。
分区数量这一项,MBR 的"4 个主分区"限制催生了扩展分区这套绕路方案:把第 4 个分区表项标记为扩展分区,然后在扩展分区内部用链表串起若干逻辑分区。逻辑分区的编号从 5 开始,中间的 2、3、4 可能空缺,这就是为什么有些机器的分区叫sda1、sda5、sda6却找不到sda2。这套机制能用,但链表结构一旦中间某个环节损坏,后面的逻辑分区全部丢失,可靠性天然差一截。
校验和备份这两项平时感知不到,出事的时候价值巨大。GPT 的头部和分区表都带 CRC32,读取时校验不过会直接报错而不是静默返回垃圾数据;主表坏了还能用备份表恢复。MBR 没有这些,分区表被写坏就是写坏了,只能靠事先备份的扇区镜像。
1.3 什么情况该选哪个:别为了怀旧选 MBR
判断逻辑其实很简单,我一般按这个顺序问自己:
- 盘容量超过 2TiB?必须 GPT,没有讨论空间。
- 机器是 UEFI 引导?系统盘必须 GPT,UEFI 固件只认 GPT 上的 EFI 系统分区。
- 需要超过 4 个分区?GPT,省得折腾扩展分区。
- 需要在很老的设备上引导,固件只支持 Legacy BIOS 且没有可靠的 GPT 引导方案?这时候 MBR 才是合理选择。
- 需要和只认 MBR 的老旧工具、老设备、老系统交换硬盘?MBR 兼容性更好。
除此之外我一律推荐 GPT。有人担心"GPT 在老机器上不能用",这个说法不准确:Linux 下 GRUB 早就支持 BIOS + GPT 引导,只是需要额外划一个 1MiB 左右的BIOS boot分区(分区类型 GUIDEF02)来存放 GRUB 的第二阶段代码。真正受限的是某些老旧的固件和工具链,不是 GPT 本身。
还有一个细节值得提:GPT 分区表在磁盘开头保留的那个保护性 MBR,类型码是0xEE,覆盖整个磁盘范围。老工具看到这个类型会认为"这块盘有个未知的超大分区",从而拒绝操作而不是直接覆盖,这层保护机制救过不少人。
1.4 双系统场景下的额外考量
如果一块盘要同时装两个系统,分区表的选择会直接影响安装顺序和引导配置。GPT + UEFI 的组合下,两个系统共用同一个 EFI 系统分区(ESP),各自的引导文件放在不同目录下,由固件的启动项管理;MBR + Legacy BIOS 的组合下,两个系统都想往 MBR 的 446 字节引导代码区写自己的引导器,后装的会覆盖先装的,需要在引导器配置里手动合并。
我的经验是:新机器、新盘,一律 GPT + UEFI,双系统共存干净得多,ESP 分区给 512MiB 到 1GiB 就够,格式化成 FAT32。老设备实在没办法才退回 MBR,并且装系统前先想清楚谁先谁后,避免引导被覆盖之后满世界找修复盘。
2. 动手前的准备:摸清家底与工具选型
2.1 lsblk、blkid、parted -l 三板斧
在动任何分区工具之前,先花三十秒把现状看清楚,这一步能避免 90% 的"手滑选错盘"。我自己固定用三条命令:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL blkid parted -llsblk给的是树状视图,一眼能看出哪块盘有哪些分区、哪个分区挂在哪里、有没有文件系统。TYPE字段特别有用,disk是整盘、part是分区、lvm是逻辑卷、crypt是加密卷,处理 LVM 或加密盘的时候必须先看清这一层,否则对着物理分区瞎操作。
blkid输出的是每个块设备的 UUID、PARTUUID、文件系统类型和标签。UUID 是文件系统级别的标识,格式化才会变;PARTUUID 是分区表级别的标识,重新分区才会变。这两个值后面写fstab都要用,先记下来。
parted -l会打印每块盘的分区表类型、扇区大小、分区起止位置。注意看Sector size那一行,logical/physical两个值不一样说明是 4K 物理扇区、512 字节逻辑扇区的盘,这种盘的 4K 对齐尤其重要,后面细说。
提示:如果机器上有正在做数据恢复或者重建阵列的盘,先别急着跑这些命令。
lsblk和blkid是只读的,安全;但parted -l在某些异常盘上会触发设备探测,操作前确认一下没有正在进行的后台任务。
还有一个隐性的坑:设备名不稳定。今天插上去是/dev/sdb,明天重启可能变/dev/sdc,加一块盘之后后面的编号全部顺移。所以我写脚本的时候从来不用sdb这种名字做判断,而是先用lsblk -dno NAME,SERIAL或者lsblk -o NAME,WWN确认序列号,再定位设备。WWN(World Wide Name)是硬盘出厂就带的唯一标识,比设备名靠谱得多。
2.2 fdisk、parted、gdisk、sgdisk 怎么挑
分区工具不是随便抓一个就行,几个主流工具的能力边界差别不小。
| 工具 | 支持 MBR | 支持 GPT | 交互式 | 脚本友好 | 适合场景 |
|---|---|---|---|---|---|
| fdisk | 是 | 是(较新版本) | 是 | 一般 | 日常手动分区,习惯老界面的首选 |
| parted | 是 | 是 | 是 | 一般 | 需要看对齐、改分区表类型、交互引导 |
| gdisk | 否 | 是 | 是 | 一般 | 纯 GPT 操作,界面与 fdisk 类似 |
| sgdisk | 否 | 是 | 否 | 极好 | 批量部署、自动化脚本 |
fdisk是老牌工具,新版本(util-linux 2.26 之后)已经合并了 GPT 支持,输g切 GPT、输o切 MBR,日常用足够了。它的优点是哪台机器都有,缺点是脚本化麻烦,得把命令通过管道喂进去。
parted的优势在于信息展示和对齐控制,unit s print free能直接把每个分区的起止扇区、空隙都列出来,判断对齐是否规范一眼就能看出来。它默认按 1MiB 对齐,对大多数场景是合适的。
gdisk是专门做 GPT 的工具,界面和 fdisk 几乎一样但只做 GPT,遇到 MBR 盘会提示转换。它的好处是分区类型代码选择极其丰富,输入L能看到一长串 GUID 类型列表。
sgdisk是 gdisk 的命令行版本,是我做批量部署时的首选。一条命令完成建表、分区、设类型、命名,可以直接塞进自动化流程:
sgdisk -Z /dev/sdb sgdisk -n 1:0:+1G -t 1:EF00 -c 1:"EFI" \ -n 2:0:+100G -t 2:8300 -c 2:"root" \ -n 3:0:0 -t 3:8300 -c 3:"data" /dev/sdb-Z清空所有分区表和残留签名,-n建分区,起点写0表示自动取上一个分区结束后的第一个对齐位置,-t设类型 GUID,-c设分区名。这套写法我在几十台机器的初始化脚本里用了很久,比交互式敲键盘可靠得多,也不会有"手抖按错一个数字"的风险。
2.3 4K 对齐:为什么起点要从 2048 扇区开始
这块值得单独拎出来讲,因为它是最容易被忽略、又最影响性能的一个细节。
现代硬盘(尤其是 SSD 和叠瓦式机械盘)的物理扇区是 4096 字节,但为了兼容老系统,对外报告的逻辑扇区通常是 512 字节。这意味着一个物理扇区对应 8 个逻辑扇区。如果分区的起始位置没有落在物理扇区的边界上,一次原本只需要写 1 个物理扇区的操作,会被拆成写 2 个物理扇区——读改写两次,性能直接腰斩,SSD 上还会额外增加写入放大,缩短寿命。
标准的对齐做法是让分区起点落在 1MiB(即 2048 个 512 字节逻辑扇区)的整数倍上。为什么是 1MiB 而不是 4KiB?因为 1MiB 同时是 4K、8K、64K、128K 的整数倍,能覆盖几乎所有 RAID 条带和 SSD 页大小的组合,是一个"通用安全值"。
算一下就明白:2048 × 512B = 1048576B = 1MiB,正好整除 4096。如果起点取 63 扇区(这是老式 MBR 的年代遗留,因为早期磁道有 63 个扇区),63 × 512 = 32256 字节,除以 4096 余 3584,完全没对齐,这就是为什么老分区方案在新盘上性能差。
parted和sgdisk默认都会做 1MiB 对齐,fdisk新版本也会在创建分区时自动选择对齐的起始扇区(显示为2048)。真正的风险在于手动指定扇区的时候,或者用一些老脚本硬编码了 63 作为起点。我见过一个批量脚本沿用十几年前的模板,所有数据盘都是 63 扇区起步,迁移到全 SSD 的机器上之后随机写性能只有正常值的一半,查了两天才定位到分区起点。
验证方式很直接:
parted /dev/sdb unit s print看每个分区的Start值能不能被 2048 整除。不能整除就是没对齐。
3. 从裸盘到可写目录的完整流程
3.1 GPT 分区实操:parted 交互式与 sgdisk 命令行
先说交互式流程。假设/dev/sdb是一块 4TB 的新盘,要划一个 512MiB 的 EFI 分区和一个占满剩余空间的数据分区。
parted /dev/sdb进入交互界面后:
(parted) mklabel gpt (parted) mkpart EFI fat32 1MiB 513MiB (parted) set 1 esp on (parted) mkpart data ext4 513MiB 100% (parted) unit s print (parted) quit几个要点。mklabel gpt会清掉原有分区表,执行前必须确认盘上没有要保留的数据。mkpart的起点写1MiB而不是0,这是为了避开 GPT 头本身占用的 LBA0 到 LBA33,同时保证 1MiB 对齐。set 1 esp on把第一个分区的类型标记为 EFI 系统分区,这一步在 UEFI 引导场景下是必须的,否则固件找不到启动分区。
对应到sgdisk的等价写法:
sgdisk -Z /dev/sdb sgdisk -n 1:2048:+512M -t 1:EF00 -c 1:"EFI" \ -n 2:0:0 -t 2:8300 -c 2:"data" /dev/sdb-n 1:2048:+512M里的2048是显式指定起始扇区,正好是 1MiB 边界。第二个分区起点写0让工具自动取对齐位置,终点写0表示用到磁盘末尾。这样建出来的两个分区,起点分别是 2048 和 1050624,都能被 2048 整除。
分区完成之后,让内核重新读取分区表:
partprobe /dev/sdb udevadm settlepartprobe触发内核重新扫描分区表,udevadm settle等 udev 把设备节点创建完。这两条命令不能省,尤其是盘正在被使用、无法卸载的情况下,不刷新内核就看不到新分区。
3.2 MBR 分区实操:主分区、扩展分区与逻辑分区
MBR 盘的操作流程类似,但因为分区数量限制,需要理解主分区和逻辑分区的区别。
fdisk /dev/sdb交互流程:
Command (m for help): o # 新建空 DOS 分区表 Command (m for help): n # 新建分区 Partition type: p # 主分区 Partition number: 1 First sector: 2048 Last sector: +100G Command (m for help): n Partition type: e # 扩展分区 Partition number: 2 First sector: (回车取默认) Last sector: (回车取默认,占满剩余) Command (m for help): n Partition type: l # 逻辑分区 First sector: (回车) Last sector: +200G Command (m for help): w # 写入这里的关键是顺序:先把 4 个主分区表项用掉之前,就决定好哪些给主分区、哪个给扩展分区。一旦扩展分区建好并写入了逻辑分区,再想改扩展分区的大小就很麻烦,往往需要先备份逻辑分区的数据再重建。
注意:
w写入之前所有操作都在内存里,随时可以q退出放弃。但一旦按下w,分区表立刻落盘,没有撤销。我养成的一个习惯是写入前先p打印一遍确认分区边界,尤其是Start和End两列,看错一位就可能覆盖掉隔壁分区。
如果用fdisk处理 GPT 盘,比较新的版本(util-linux 2.26+)直接支持,进界面后输g建 GPT 表即可。版本老一些的fdisk会把 GPT 盘里的保护性 MBR 当成一个0xEE类型的分区显示,这时候千万别手贱去删它,会破坏 GPT 结构。拿不准版本的话,直接换parted或gdisk更保险。
3.3 格式化:mkfs 家族选型与关键参数
分区建好只是有了"容器",要往里放文件还得格式化,也就是建立文件系统。
选哪个文件系统,我的判断标准是:
| 文件系统 | 优势 | 劣势 | 典型用途 |
|---|---|---|---|
| ext4 | 成熟稳定、可缩容、工具链完整 | 大文件和高并发写性能一般 | 系统盘、通用数据盘 |
| XFS | 大文件、大目录、高并发性能好 | 不支持缩容 | 数据库、日志、大容量数据盘 |
| Btrfs | 支持快照、子卷、校验 | 复杂场景稳定性争议 | 需要快照和回滚的场景 |
| FAT32 | 兼容性极好 | 单文件 4GiB 上限、无权限 | EFI 系统分区、U 盘 |
| NTFS | 与另一类系统互通 | Linux 下写入性能一般 | 双系统共享分区 |
格式化 ext4 的完整命令:
mkfs.ext4 -L data -m 1 -E lazy_itable_init=1,nodiscard /dev/sdb2参数逐个说。-L data给分区打标签,之后可以用LABEL=data挂载,比记 UUID 直观。-m 1把保留块比例从默认的 5% 降到 1%,这一项在大容量盘上省的空间非常可观:一块 4TB 的数据盘,5% 就是 200GB 白白留着只给 root 用,降到 1% 只需要 40GB,省下 160GB。保留块的初衷是防止普通用户把根分区写满导致系统无法运转,数据盘完全没必要留这么多。
-E lazy_itable_init=1,nodiscard是加速格式化的。lazy_itable_init让 inode 表的初始化延后到后台进行,nodiscard跳过格式化时的 discard 操作。这两项能让 TB 级盘的格式化时间从几十分钟缩短到几秒。代价是格式化刚完成的短时间内,后台还在做初始化,性能会有一点波动,问题不大。
如果这块盘会放在 RAID 阵列或者有明确条带参数的存储上,还应该显式指定条带参数:
mkfs.ext4 -E stride=128,stripe-width=256 /dev/sdb2stride是文件系统块数对应的条带大小,stripe-width是一个完整条带跨越的磁盘数。举例来说,RAID5 有 4 块盘、条带 512KiB,那么 stride = 512KiB / 4KiB = 128,stripe-width = 128 × (4-1) = 384。算错这两个参数不会报错,但会导致写入时跨越条带边界,性能下降。拿不准的话不指定反而安全,文件系统会按默认值走。
格式化 XFS:
mkfs.xfs -f -L data -d su=512k,sw=3 /dev/sdb2-f强制覆盖已有文件系统,因为 XFS 检测到旧签名会拒绝操作。su和sw对应条带单元和条带宽度,含义和 ext4 的 stride 类似。注意 XFS 不支持缩容,这是选它之前必须确认的一点——如果这个分区未来可能需要缩小,老老实实用 ext4。
格式化 EFI 分区用的是 FAT32:
mkfs.fat -F32 -n EFI /dev/sdb13.4 挂载与 fstab 持久化:UUID 才是正解
格式化完成后,先临时挂载验证能用:
mkdir -p /data mount /dev/sdb2 /data df -hT /datadf -hT里能看到挂载点、文件系统类型、容量和使用率,确认无误之后再写持久化配置。
注意:临时挂载和持久化配置是两件事。
mount命令只在当前运行期有效,重启就没了。要让挂载在开机时自动生效,必须写进/etc/fstab。很多人格式化完用mount挂上就以为完事了,机器一重启目录变空,还以为数据丢了,其实只是没挂载。
写fstab之前先拿到 UUID:
blkid /dev/sdb2输出类似:
/dev/sdb2: LABEL="data" UUID="a1b2c3d4-..." TYPE="ext4" PARTUUID="..."然后在/etc/fstab里追加一行:
UUID=a1b2c3d4-... /data ext4 defaults,noatime,nofail 0 2为什么用 UUID 而不是/dev/sdb2?因为设备名会漂移。今天这块盘是sdb,明天加一块盘可能变sdc,fstab里的/dev/sdb2就指到了别的分区,运气好挂载失败,运气不好挂载了错误的盘,往里面写数据就是灾难。UUID 是格式化时生成并写进文件系统超级块的,只要不重新格式化就不会变,稳定得多。
PARTUUID和UUID的区别要注意:PARTUUID来自分区表,重新分区会变;UUID来自文件系统,重新格式化会变。日常挂载文件系统用UUID就对了。
挂载选项里,noatime表示不更新文件的访问时间。默认的relatime已经够用,但noatime在高频读取的场景下能减少一些元数据写入,对 SSD 友好。nofail是关键:它告诉系统即使这块盘挂载失败,也继续正常启动,不要卡在紧急维护模式。对于非系统盘的数据盘,这个选项几乎是必加的,否则一块盘掉线就能让整台机器起不来。
最后两个数字,第一个是 dump 备份标志,基本永远写0;第二个是开机自检顺序,根分区写1,其他 ext 系分区写2,XFS 和 Btrfs 这类不需要开机自检的写0。
写完不是立刻重启验证,先用这条命令做语法和挂载测试:
mount -o remount /data # 或者 umount /data && mount -amount -a会尝试挂载fstab里所有未挂载的条目,有错误当场报出来。这一步通过之后才算稳妥。改动fstab之后还建议跑一次systemctl daemon-reload,让 systemd 重新生成对应的 mount 单元,否则有些依赖关系不会立即更新。
如果盘是热插拔的、或者来自外部存储,建议再补一个超时选项:
UUID=a1b2c3d4-... /data ext4 defaults,noatime,nofail,x-systemd.device-timeout=10 0 2十分钟的默认等待时间太长,开机卡在那里转圈很难受,设成 10 秒,等不到就直接跳过。
4. 现场踩坑与排查记录
4.1 分区表改了,内核没反应
这是最高频的问题:fdisk或parted里明明建好了分区,lsblk也显示了,但mkfs报找不到设备,或者/dev/sdb1就是不存在。
原因通常是内核还在用旧的分区表缓存。分区表写进磁盘之后,内核需要一次"重新扫描"的动作才能感知。几种处理方式按推荐顺序:
partprobe /dev/sdb udevadm settle如果partprobe也不行,说明这块盘的某个分区正被占用,内核拒绝重新扫描。这时候可以尝试:
blockdev --rereadpt /dev/sdb还是不行就只能卸载相关分区再试,或者重启。这种情况在系统盘上操作时特别常见,因为根分区一定被占用,改分区表之后只能重启生效。
另一个相关的坑是设备节点没生成。lsblk显示分区存在但/dev/下没有对应节点,一般是 udev 规则出了问题,udevadm settle或者udevadm trigger能解决。如果反复出现,检查一下是不是把 udev 服务停了。
4.2 几种典型挂载报错逐条拆解
报错一:mount: /data: wrong fs type, bad option, bad superblock
这个报错信息很笼统,可能的原因有好几个。先确认分区上真的有文件系统:
blkid /dev/sdb2如果什么都没输出,说明没格式化,或者格式化写到了别的地方。如果输出了TYPE="ext4"但挂载报超块错误,可能是格式化被中断了,重新格式化。
还有一种隐蔽情况:分区表上残留着旧的签名。比如这块盘以前做过 LVM 或者 RAID 成员,分区头部留着 PV 签名或 RAID 超级块,mkfs拒绝覆盖。这时候用:
wipefs -a /dev/sdb2清掉所有已知签名再格式化。我在复用退役盘的时候遇到过好几次,blkid显示TYPE="linux_raid_member",明明只想当普通分区用,必须先wipefs。
报错二:mount: /data: target is busy
挂载点被占用了。常见于想重新挂载到一个已经有进程在里面工作的目录。用lsof +D /data或者fuser -mv /data找出占用进程,停掉之后再操作。如果只是想换一块盘挂到同一个位置,正确顺序是umount再mount,而不是直接mount覆盖。
报错三:挂载成功但只读
用mount看一眼实际挂载参数里有没有ro。出现只读挂载通常是文件系统检测到错误后自动降级保护,dmesg里会有对应记录,比如EXT4-fs error或者corruption。这时候别急着mount -o remount,rw,先看日志搞清楚错误类型,该跑fsck就跑:
umount /dev/sdb2 fsck.ext4 -f /dev/sdb2-f是强制执行,即使文件系统看起来干净也检查。检查完再挂载。
报错四:容量对不上,少了一大截
排除文件系统本身的元数据开销之后,如果少得离谱,检查两件事:分区是不是没占满整盘(parted unit s print free看尾部有没有大段 Free Space),以及格式化时是不是设了过大的保留块比例(tune2fs -l /dev/sdb2 | grep -i reserved看Reserved block count)。前者重新划分区,后者用tune2fs -m 1 /dev/sdb2在线调整。
4.3 fstab 写崩之后的自救流程
fstab写错导致机器起不来,是这套操作里后果最严重的一个。系统启动时如果某个fstab条目的设备找不到又没有nofail,会掉进紧急维护模式,屏幕上只有一行 root 密码提示。看到这个界面别慌,按这个顺序处理:
第一步,输入 root 密码进入单用户 shell。如果连密码提示都没有,需要在引导菜单里给内核加rd.break或init=/bin/bash参数进救援模式。
第二步,根文件系统此时通常是只读挂载的,先重新挂成可写:
mount -o remount,rw /第三步,直接编辑fstab,把有问题的那一行注释掉:
vi /etc/fstab不确定是哪一行的话,用mount -a逐条测试,报错的那条就是问题所在。
第四步,改完重启:
systemctl reboot为了减少这种情况,我现在的做法是:所有非系统盘一律加nofail;改fstab之后一定先mount -a验证;远程机器上改fstab之前先开一个保持连接的会话,防止改崩之后 SSH 也断了没法救。
还有一个更隐蔽的坑:用mount -a验证通过了,重启却卡住。原因可能是设备在启动早期还没就绪,systemd 等设备超时。加x-systemd.device-timeout=10或者把挂载改成noauto,x-systemd.automount按需挂载能解决。
4.4 常见问题速查表
| 现象 | 最可能原因 | 处理动作 |
|---|---|---|
分区后/dev/sdbN不存在 | 内核未重新扫描分区表 | partprobe+udevadm settle |
mkfs报设备忙 | 分区已挂载 | umount后重试 |
mkfs提示已有签名 | 残留 LVM/RAID 元数据 | wipefs -a清理 |
| 挂载报超块错误 | 未格式化或格式化中断 | blkid确认后重新格式化 |
| 挂载成功但只读 | 文件系统检测到错误 | 看dmesg,跑fsck |
| 容量少很多 | 分区未占满盘或保留块过高 | parted print free、tune2fs -m |
| 重启后目录为空 | 未写fstab或写错 | 检查fstab,mount -a验证 |
| 开机卡在紧急模式 | fstab有无法挂载的条目 | 单用户模式注释掉该行 |
| 分区起点未对齐 | 手动指定了非 2048 倍数的扇区 | 备份数据后重建分区 |
5. 长期用得住的几个习惯
5.1 分区规划:一开始就留好余地
分区方案我踩过最大的坑是"一次规划用到底"。刚开始做数据盘的时候习惯整块盘一个分区,用了一年数据涨上来需要分离日志和备份,就得把数据倒出来重新分区,几百 GB 的搬迁一次就是大半天。
现在我的做法是,盘容量超过 2TB 就至少分两个区,一个放热数据、一个放冷数据或备份。不是为了现在,是为了半年后想调整的时候能少折腾。如果对未来的容量增长完全没概念,更好的方案是不分区、直接上 LVM:物理卷铺满整盘,上面切逻辑卷,扩容时lvextend一条命令就搞定,不用碰分区表。
LVM 的额外好处是能把多块盘合成一个卷组,逻辑卷跨盘分布。代价是多一层映射,性能有极小的损耗,并且盘坏了恢复更麻烦——逻辑卷横跨多盘的时候,一块盘挂了整个卷组都受影响。所以我的选择是:单盘用普通分区,多盘组池用 LVM,不混着来。
5.2 备份分区表:出事之后能救命
GPT 自带备份,主表坏了还能从磁盘末尾的备份恢复,但这需要工具配合。更简单的做法是直接备份分区表扇区:
sgdisk --backup=/root/sdb-gpt-backup.bin /dev/sdb恢复:
sgdisk --load-backup=/root/sdb-gpt-backup.bin /dev/sdbGB 级的备份文件也就几 KB,扔在任何地方都不占空间。我一般在分区完成后立刻备份一份,之后每次改分区表再备一次,文件名带上日期。
MBR 盘的备份用dd:
dd if=/dev/sdb of=/root/sdb-mbr-backup.bin bs=512 count=1只备份第一个扇区,包含引导代码和分区表,正好 512 字节。恢复时反过来dd回去。
提示:分区表备份只能恢复分区结构,不能恢复数据。分区表丢失之后,正确的顺序是先备份恢复分区表、确认分区边界和原来一致,再去考虑数据的事。顺序搞反了,用错误的边界去写数据,可能把原本还在的数据覆盖掉。
5.3 扩容、缩小与回收的那些坑
扩容磁盘空间,分两种情况。如果盘本身没变,只是分区没占满,用growpart扩展分区再扩文件系统:
growpart /dev/sdb 2 resize2fs /dev/sdb2 # ext4 xfs_growfs /data # XFSgrowpart会自动处理分区表扩展,比手动parted resizepart安全。注意 XFS 的扩容命令参数是挂载点而不是设备,xfs_growfs /data才对,写设备名会报错。
如果盘本身换了更大的,比如云上扩容了云盘,流程是一样的:先让内核重新识别磁盘大小(有些环境需要重启或者echo 1 > /sys/class/block/sdb/device/rescan),再growpart,再扩文件系统。
缩容是另一回事。ext4 支持缩容但必须卸载后离线操作,顺序是e2fsck -f、resize2fs缩文件系统、最后缩分区。顺序绝对不能反:先缩分区后缩文件系统,文件系统的尾部元数据直接被切掉,数据报废。XFS 压根不支持缩容,需要缩小只能备份、重建、恢复。
回收一块退役盘的时候,我固定跑三个动作:wipefs -a清签名、sgdisk -Z清分区表、看一眼 SMART 状态决定这盘还能不能继续用。最后一步特别重要,一块已经出现重映射扇区的盘,就算擦干净了也别放进生产环境,用在测试机上都嫌它随时掉线添乱。
5.4 一个容易忽略的收尾动作
新盘挂载完、数据写进去之后,很多人就结束了。我的习惯是再确认两件事:一是systemd-analyze里检查有没有慢启动的挂载单元,二是跑一次重启验证。
第一件事查的是开机耗时里有没有被某个挂载拖累,systemd-analyze blame里如果看到data.mount排在前几位,说明这块盘初始化慢,需要调整超时或者改成按需挂载。
第二件事更朴素但最有效:真的重启一次。临时挂载、mount -a验证都通过,和重启后能正常起来是两码事,中间隔着设备就绪顺序、systemd 单元依赖这些只在启动阶段才暴露的问题。我在流程里加这一步之后,fstab导致的线上事故基本清零了。