0x00 一个看似无害的操作,引爆了一场灾难
事情是这样的。我的笔记本是 Windows + Ubuntu (Kubuntu) 双系统,配置如下:
磁盘0(NVMe 953GB):
- p1: 100MB EFI System Partition (Windows ESP)
- p2: 16MB Microsoft Reserved
- p3: 127.3GB C盘 (NTFS, BitLocker加密)
- p4: 704MB Windows恢复分区
- p5: 320GB D盘预留空间 (NTFS, BitLocker加密但从未格式化使用)
- p6: 384MB EFI System Partition (Ubuntu ESP)
- p7: 480GB Linux filesystem (Ubuntu根分区,Btrfs文件系统)
- p8: 25.4GB Linux swap
- 磁盘1(476GB):exFAT外置U盘,与系统无关
那个320GB的p5分区是我当初装双系统时特意留给D盘的,但因为我一直主要在Linux环境下开发学习,就忘了格式化它。某天心血来潮想用Windows磁盘管理把它格式化成NTFS当真正的D盘用——结果重启后,Ubuntu再也进不去了。
开机直接掉进 grub> 命令行,无论怎么 insmod part_gpt、insmod ext2、insmod btrfs、ls 各个分区,统统报 unknown filesystem。
我当时的心态:完了,是不是硬盘坏了?是不是要重装系统了?我那480GB的开发环境、代码、课程作业……
0x01 诊断误区——为什么在 grub> 里救不了
最初的尝试和失败
我天真地以为可以在GRUB命令行里手动指定内核路径启动,就像网上教程说的那样。于是我照着做:
grub> insmod part_gpt
grub> insmod ext2
grub> ls
(memdisk) (hd0) (hd0,gpt1) (hd1)
grub> ls (hd0,gpt1)/
error: unknown filesystem.
grub> insmod btrfs
grub> ls (hd0,gpt1)/
error: unknown filesystem.诡异现象1: ls 只列出了一个 (hd0,gpt1),而且这个分区还是 unknown filesystem。可我明明有8个分区啊!
诡异现象2: 出现了 (memdisk) 设备——这玩意儿正常情况下不该出现在硬盘启动的环境里。
诡异现象3: 即使我加载了所有文件系统模块(ext2、btrfs、fat),依然读不出任何分区内容。
真相浮出水面
后来我才明白,这三个"诡异"其实指向同一个根源:
(memdisk)的来源:我的LiveUSB是用Ventoy制作的,Ventoy的引导机制会往内存注入虚拟磁盘来加载ISO镜像。所以当时那个grub>很可能根本不是硬盘Ubuntu的GRUB,而是被Ventoy环境污染过的混乱状态。- 只显示一个分区的真正原因:GPT主头损坏了。GRUB的
part_gpt驱动解析器非常脆弱,一旦主头CRC校验失败,它就直接放弃,不会像Linux内核那样智能回退去读备份头。于是在GRUB眼里,这块盘"没有可用分区"。 - 为什么加载再多模块也没用:因为问题不在文件系统识别能力,而在于压根就没找到分区在哪。
关键教训
不要在
grub>/grub rescue>里浪费时间试图手动引导Btrfs分区。GRUB命令行对Btrfs的支持本来就残缺(无法优雅切换subvolume),再加上GPT主头损坏导致分区枚举失败,这条路从一开始就是死的。正确做法是直接上LiveUSB,用功能完整的Linux环境修复。
0x02 用Linux内核视角穿透"空白分区"的伪装
Windows磁盘管理的误导性显示
插上Ubuntu安装U盘,进入Try Ubuntu模式,打开终端第一件事就是看分区情况。但我手头只有Windows那边的信息作为参照——之前在Windows磁盘管理里看到的样子是这样的:
| 卷标/名称 | 容量 | 文件系统 | 状态 |
|---|---|---|---|
| (C:) | 127.31 GB | NTFS (BitLocker) | 状态良好 |
| (E:) | 476.92 GB | exFAT | 状态良好 |
| 磁盘0分区1 | 100 MB | — | 状态良好(EFI系统) |
| 磁盘0分区4 | 704 MB | — | 状态良好(恢复分区) |
| 磁盘0分区6 | 384 MB | — | 状态良好(EFI系统) |
| 磁盘0分区7 | 480 GB | — | 状态良好(主分区) |
| 磁盘0分区8 | 25.38 GB | — | 状态良好(主分区) |
| 新加卷(D:) | 320 GB | NTFS (BitLocker) | 状态良好 |
注意那几个"状态良好(主分区)"且文件系统一栏空白的家伙——p6/p7/p8。
这就是最大的迷惑点:Windows不认识Linux的文件系统(ext4/btrfs/swap),遇到就显示成"未知类型的主分区",既不报错也不标注具体格式。很多人一看"未知"+"主分区"就慌了:"是不是坏了?要不要初始化?"
千万别! 这正是你的Ubuntu藏身之处。
用 lsblk -f 还原真实面貌
回到LiveUSB终端,执行:
lsblk -f输出(节选):
NAME FSTYPE LABEL UUID MOUNTPOINT
nvme0n1
├─nvme0n1p1 vfat FAT32 40E0-01F9 ← Windows ESP
├─nvme0n1p2 ← MS保留
├─nvme0n1p3 BitLocker 7147d05e-c146-430c-8bb2-bd5afb4ee5fc ← C盘
├─nvme0n1p4 ntfs 7830C36030C323CA ← 恢复分区
├─nvme0n1p5 BitLocker 11d33bad-b1ab-4bb9-bbcf-f6de461f4bf3 ← D盘预留
├─nvme0n1p6 vfat FAT32 40F8-3C82 ← Ubuntu ESP ✨
├─nvme0n1p7 btrfs b5ef84f3-cce2-4cc8-8022-622e4a6927c0 ← Ubuntu根(Btrfs)✨
└─nvme0n1p8 swap 1 0696a29e-62a7-46f8-ac12-f43212e6b14e ← Swap ✨一目了然:p7是Btrfs格式的480GB根分区,p8是25.4GB交换分区,p6是384MB的Ubuntu专用ESP。它们在Windows眼里是"未知主分区",但在Linux内核面前无所遁形。
另一个坑:blkid 居然看不到分区节点
正当我以为大局已定时,又发现一个新问题:
sudo blkid输出里 /dev/nvme0n1 那一行只有 PTTYPE="gpt",后面一个分区都没列出来!这意味着虽然fdisk/parted这类用户态工具能读到扇区上的GPT字节并解析出8个分区,但Linux内核此刻拒绝为它们创建 /dev/nvme0n1pX 设备节点。
这就解释了为什么之前 mount /dev/nvme0n1p7 会失败——节点根本不存在嘛!
为什么会这样? GPT在设计上有两份目录:主头在盘首(前几个扇区),备份头在盘尾(最后几个扇区)。正常工作时两者互为冗余。但如果主头的CRC校验位损坏,不同工具的容忍度就不一样了:
- fdisk/gdisk等用户态工具:检测到主头坏 → 自动回退读备份头 → 照样能列出分区;
- Linux内核:检测到主头坏 → 保守起见直接罢工,不建节点(除非你强制让它重扫);
- GRUB的part_gpt驱动:检测到主头坏 → 彻底懵逼,认为"这块盘没分区"。
所以当时的局面是:数据完好、分区边界清晰、Windows还能正常启动,唯独GRUB和内核都不认账。
0x03 确诊病因——GPT主头损坏而非数据丢失
决定性证据:fdisk 的一句英文提示
为了搞清楚到底是哪种损坏,我在LiveUSB终端跑了:
sudo fdisk -l /dev/nvme0n1第一行赫然写着:
The primary GPT table is corrupt, but the backup appears OK, so that will be used.翻译成人话:主GPT表已损坏,但备份表看起来完好,因此将改用备份表读取分区信息。
这句话瞬间把所有疑团串联起来了:
- ✅ 为什么Windows磁盘管理和KDE Partition Manager都能看到8个分区?因为它们都是用户态直读扇区,fdisk告诉它们的逻辑一样——主头坏就用备份头。
- ❌ 为什么
blkid和mount一开始失败了?因为内核没这么聪明,它看见主头坏就直接放弃了。 - 💀 为什么GRUB完全瞎了?因为它的
part_gpt驱动比内核还固执,连回退都不会。
结论:这不是硬件故障,不是数据丢失,只是分区表的"封面"破了,而"封底"还好好的。 修复方法就是用gdisk把完好的备份头复制回主头位置,让三者(内核、GRUB、Windows)都满意。
Btrfs子卷结构的额外确认
既然根分区是Btrfs而不是常见的ext4,还有个特殊考量:Btrfs的文件系统UUID存储在superblock里,移动/压缩分区不会改变它。这是个好消息——意味着我的 /etc/fstab 里的UUID大概率还是对的,不用大改。
但Btrfs也有个麻烦:挂载时必须显式指定subvolume。Ubuntu默认的Btrfs布局通常是:
@→ 根目录/@home→ 家目录/home- (可能还有
@snapshot等其他子卷)
如果裸挂或者依赖default subvolume,很容易挂到顶层空壳,看不到真正的 /etc、/boot。
为了摸清结构,我先做了只读探测:
sudo mkdir -p /mnt/probe
sudo mount -o subvolid=5 /dev/nvme0n1p7 /mnt/probe # 挂到顶层看全貌
ls -la /mnt/probe
sudo btrfs subvolume list /mnt/probe
sudo btrfs subvolume get-default /mnt/probe
sudo umount /mnt/probe输出证实了我的猜测:
ID 256 gen 26393 top level 5 path @ ← 根子卷
ID 257 gen 26392 top level 5 path @home ← 家目录子卷
ID 258 gen 24911 top level 5 path @swap ← swapfile所在子卷
Default subvolume: ID 5 (FS_TREE) ← ⚠️ 默认是顶层!关键点:get-default 返回的是 FS_TREE(即顶层),而不是 @。这意味着挂载根分区时必须手动加 -o subvol=/@,绝不能偷懒裸挂。
接下来验证fstab是否正确:
sudo mount -o subvol=/@ /dev/nvme0n1p7 /mnt/probe
cat /mnt/probe/etc/fstab
sudo umount /mnt/probefstab全文(节选核心部分):
UUID=40F8-3C82 /boot/efi vfat defaults 0 2
UUID=b5ef84f3-cce2-4cc8-8022-622e4a6927c0 / btrfs subvol=/@,defaults,noatime,autodefrag 0 0
UUID=b5ef84f3-cce2-4cc8-8022-622e4a6927c0 /home btrfs subvol=/@home,defaults,noatime,autodefrag 0 0
UUID=b5ef84f3-cce2-4cc8-8022-622e4a6927c0 /swap btrfs subvol=/@swap,defaults 0 0
UUID=0696a29e-62a7-46f8-ac12-f43212e6b14e swap swap defaults 0 0
/swap/swapfile swap swap defaults 0 0三个UUID与 lsblk -f 实测值逐一吻合:
- p7 (Btrfs):
b5ef84f3-cce2-4cc8-8022-622e4a6927c0✓ - p6 (ESP):
40F8-3C82✓ - p8 (Swap):
0696a29e-62a7-46f8-ac12-f43212e6b14e✓
太好了,fstab一个字都不用改! 正如我之前分析的,Btrfs的FS UUID不受分区位移影响,这次侥幸躲过了一劫。
0x04 终极修复三部曲
现在障碍只剩最后一个:GPT主头还没修好。只要跨过这道坎,剩下的就是标准的chroot重装GRUB流程了。
Step 1: 用gdisk重写主头
sudo apt update && sudo apt install -y gdisk
sudo gdisk /dev/nvme0n1进入交互界面后,严格按照以下按键操作(切记不要乱按其他键):
- 按
p回车 → 打印当前分区表,核对是否是8个分区、大小是否与预期一致; - 确认无误 → 按
w回车 → 系统询问Do you want to write...? (Y/N)→ 按Y回车; - gdisk会将内存中(来自完好备份头的)正确分区表同时写回主头和备份头,并重新计算CRC校验位。
⚠️ 红线警告:全程只允许按 p 和 w。绝对禁止触碰以下杀手键:
o: 创建新的空白分区表(清空一切)z: 销毁GPT结构(不可逆)d: 删除分区n: 新建分区(可能导致重叠覆盖)
做完后再跑一次验证:
sudo fdisk -l /dev/nvme0n1 2>&1 | head -3这次第一行干干净净,不再有 corrupt 字样了。病根①解除。
Step 2: chroot进入Ubuntu环境重建引导
# 挂载Ubuntu根分区(务必带subvol参数!)
sudo mkdir -p /mnt/probe
sudo mount -o subvol=/@,noatime,autodefrag /dev/nvme0n1p7 /mnt/probe
# 挂载Ubuntu的ESP(注意是p6不是p1!)
sudo mkdir -p /mnt/probe/boot/efi
sudo mount /dev/nvme0n1p6 /mnt/probe/boot/efi
# 绑定运行时必需的伪文件系统
for i in dev dev/pts proc sys run; do
sudo mount --bind /$i /mnt/probe/$i
done
# 让efivarfs可写(用于更新UEFI固件启动项)
sudo mount -t efivarfs efivarfs /mnt/probe/sys/firmware/efi/efivars 2>/dev/null || true
# 进入chroot
sudo chroot /mnt/probe /bin/bash此时提示符变为 root@kubuntu:/#,我们已经身处真实的Ubuntu环境中。
Step 3: 治本三连击
在chroot内依次执行:
# 1) 核对fstab中的UUID是否仍然有效(应该原样输出,无需修改)
grep -E 'b5ef84f3|40F8-3C82|0696a29e' /etc/fstab
# 2) 重建initramfs(确保Btrfs驱动和新root定位方式被打入早期启动镜像)
update-initramfs -u -k all
# 3) ★核心★ 重装GRUB本体(解决core image物理定位过期的问题)
grub-install --target=x86_64-efi \
--efi-directory=/boot/efi \
--bootloader-id=ubuntu \
--recheck
# 4) 重新生成GRUB配置文件(扫描/boot下的内核和initrd,构建菜单)
update-grub
# 5) 检查UEFI固件是否收到新的启动项
efibootmgr -v | grep -i ubuntu每一步的预期输出:
Step 2 应该生成两个内核的initramfs:
update-initramfs: Generating /boot/initrd.img-7.0.0-38-generic
update-initramfs: Generating /boot/initrd.img-7.0.0-34-genericStep 3 最关键,应该报告:
Installing for x86_64-efi platform.
Installation finished. No error reported.这句"No error reported"意味着GRUB的core image已成功嵌入ESP并重写了所有必要的EFI二进制文件(shimx64.efi、grubx64.efi等)。病根②解除。
Step 4 应该找到所有内核并生成完整菜单:
Found linux image: /boot/vmlinuz-7.0.0-38-generic
Found initrd image: /boot/initrd.img-7.0.0-38-generic
Found linux image: /boot/vmlinuz-7.0.0-34-generic
Found initrd image: /boot/initrd.img-7.0.0-34-generic
Found memtest86+ ...
Warning: os-prober will be executed to detect other bootable partitions...
Found Windows Boot Manager on /dev/nvme0n1p1@/efi/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings ...
done惊喜来了!os-prober居然检测到了Windows Boot Manager! 尽管C盘和D盘都是BitLocker加密的,但p1那个FAT格式的ESP里的 bootmgfw.efi 引导文件是明文的,不需要解密就能被发现。这意味着重启后GRUB菜单里会有Windows选项,不用再单独按F12选了。
Step 5 见证最终胜利:
Boot0000* Kubuntu HD(6,GPT,...)/\EFI\ubuntu\shimx64.efi解读这条记录:
Boot0000*: 星号表示激活状态,编号0000说明排在启动顺序第一位;HD(6,...): 指向第6个分区(正是我们的Ubuntu ESP p6);\EFI\ubuntu\shimx64.efi: 正确的Secure Boot兼容引导链入口。
至此,整条链路彻底打通:GPT主头✓ → GRUB core✓ → EFI启动项✓ → NVRAM注册✓。
退出chroot并卸载:
exit
sudo umount -R /mnt/probe0x05 重启验收——从绝望到狂喜
拔掉LiveUSB(避免Ventoy污染启动流程),按下Ctrl+Alt+Del。
屏幕亮起的那一刻,我的心提到了嗓子眼。熟悉的BIOS Logo闪过,紧接着——
GRUB菜单出现了!
黑底白字的经典界面,上面整齐排列着:
Ubuntu
Advanced options for Ubuntu
Windows Boot Manager
UEFI Firmware Settings选中第一项 Ubuntu,回车。进度条飞速滚动,几秒钟后,Kubuntu登录界面温柔地浮现。输入密码,进入桌面。
打开Dolphin文件管理器,导航到我的项目文件夹 ~/文档/Proj03——那些 .cpp 源代码、.docx 课程报告、编译产物,全都安安静静地躺在那里,一个字节都没少。
打开Konsole终端,敲下 uname -r,返回 7.0.0-38-generic。再敲 df -hT | grep btrfs,看到根分区稳稳挂载在 /dev/nvme0n1p7 上,类型为 btrfs。
成功了。彻彻底底地成功了。
0x06 复盘:这场灾难的本质是什么?
回头来看,整个事故链条其实很简单:
- 诱因:在Windows磁盘管理中格式化了一个从未使用的320GB预留分区(p5);
- 连锁反应:格式化操作涉及写入分区表元数据,可能在某个环节打断了GPT主头的原子性更新,导致其CRC校验位损坏;
症状爆发:
- Windows自己不受影响(因为它有自己的ESP p1,且不依赖Ubuntu分区);
- Linux内核启动时发现主头坏但不肯回退,于是拒绝创建分区节点;
- GRUB更惨,直接两眼一抹黑,掉进
rescue>模式;
- 修复关键:认识到这只是"封面破损"而非"书籍丢失",用gdisk从完好的备份头恢复主头,再标准流程重装GRUB即可。
整个过程没有动用任何数据恢复工具(TestDisk/PhotoRec之类),因为没有必要——数据一直都在,只是索引暂时失效了。
给后来者的忠告
如果你也遇到了类似的 grub> unknown filesystem 困境,请记住以下几点:
🚫 千万不要做的事
- 不要在
grub>/grub rescue>里死磕:尤其是Btrfs用户,GRUB命令行的subvolume支持太差,效率极低且容易误操作; - 不要格式化任何"看起来奇怪"的分区:Windows显示的"未知主分区"很可能就是你的Linux根分区;
- 不要在KDE Partition Manager/GParted里点Apply:当它们显示Type为unknown时,贸然应用变更可能真的改写分区边界;
- 不要运行
mkfs.btrfs/mkfs.ext4:即使挂载失败也不要怀疑是文件系统坏了,先排查分区表和挂载参数; - 不要在gdisk里乱按键:
o/z/d/n任何一个都是一键毁尸灭迹。
✅ 一定要做的事
- 第一时间制作LiveUSB:用官方Ubuntu/Kubuntu ISO,推荐Ventoy或balenaEtcher;
- 优先以UEFI模式启动LiveUSB:否则后续efibootmgr/grub-install全部失效;
- 用
lsblk -f和sudo blkid看清真实身份:不要被Windows的"未知"表象迷惑; - Btrfs用户必须先探测subvolume结构:
btrfs subvolume list+get-default,确认根子卷名字(通常是@); - 挂载根分区永远带上
-o subvol=/@:这是Btrfs修复的头号命门; - 区分"主头损坏"和"数据丢失":前者用gdisk几秒搞定,后者才需要专业恢复手段;
- 修复顺序严格遵循:先修GPT → 再chroot → 然后update-initramfs → 接着grub-install → 最后update-grub;
- 善用
fdisk的诊断能力:它会明确告诉你主头是否corrupt、备份是否OK,这是最快的确诊方式。
💡 预防胜于治疗
定期备份分区表:
sudo sgdisk --backup=nvme-partition-table.bak /dev/nvme0n1- 重要变更前先用
gparted模拟演练:它会显示将要调整的起止扇区,让你心中有数; - 考虑启用Timeshift快照:Btrfs的原生子卷快照功能可以做到分钟级系统回滚;
- 双系统尽量分离ESP:像我这样Windows用p1、Ubuntu用p6的设计,即使一方炸了另一方也能独善其身;
- 谨慎对待"未使用的大分区":如果要格式化长期闲置的空间,最好先从Linux侧操作(GParted),它对跨平台文件系统更安全。
0xff 结语:技术之外的心得
这次救援历时数小时,跨越十余轮对话,从最初的惊慌失措到最后的从容淡定,我深刻体会到几点:
第一,冷静是最大的武器。 面对 grub> unknown filesystem 这种恐怖画面,最容易犯的错误就是病急乱投医——格式化、重装、甚至砸键盘。但只要记住"数据还在盘上躺着"这个基本事实,就有底气一步步抽丝剥茧。
第二,工具的选择决定成败。 同样是查看分区,Windows磁盘管理给你的是迷雾,Linux的 lsblk -f 给你的是真相;同样是修复引导,在 grub> 里摸索是缘木求鱼,在LiveUSB里chroot才是正道。工欲善其事必先利其器,这话永不过时。
第三,知识储备的价值在此刻具象化了。 如果我事先不了解"Btrfs的FS UUID不随分区移动而变化"这个特性,可能会徒劳地去修改fstab;如果我不知道"GPT有主备双头"的设计哲学,可能会被fdisk那句英文提示吓得魂飞魄散。每一个看似冷门的细节,关键时刻都能救命。
第四,社区的力量无可替代。 这篇文章的记录过程本身就是一次复盘和学习。希望它能帮助下一个在深夜对着黑屏发呆的人,告诉他:别怕,你的数据还在,跟我一起把它找回来。
最后,感谢那个没有放弃的自己。🍻
(End)
PS:这次修复本来是想找大肥鱼寻求帮助的,但是“屋漏偏逢连夜雨”,Deepseek 在那时候出现故障了qwq,最后找的千问协助排查的(abab)


没有评论