Linux分区破坏的修复

服务器误操作,删除了系统盘 /dev/sda 上的分区,误操作步骤如下:

fdisk /dev/sda

然后执行了 g 命令 - g create a new empty GPT partition table

此时服务器还没有重启,使用 fdisk -l 可以看到sda磁盘分区没有了

# fdisk -l
Disk /dev/sda: 745.2 GiB, 800166076416 bytes, 1562824368 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 3F269632-A490-4E27-87D3-3677667E3C6C

不过,系统还没有重启,当前磁盘还挂载:

# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        126G     0  126G   0% /dev
tmpfs           126G   76K  126G   1% /dev/shm
tmpfs           126G   11M  126G   1% /run
tmpfs           126G     0  126G   0% /sys/fs/cgroup
/dev/sda1        50G  7.2G   41G  15% /
/dev/sda2       296G   63M  295G   1% /home
tmpfs            26G   16K   26G   1% /run/user/0
  • 挂载情况

  • 内核中显示分区信息还在

  • 检查 /etc/fstab 内容如下

  • 检查uuid

  • 通过blkid可以得知原先的分区表是msdos

通过lsblk也可以直接获得所有分区的uuid

但是需要注意 /dev/sda 被覆盖成GPT了

  • 内核中磁盘分区信息

关键是如何恢复磁盘中的分区表,在操作系统还没有重启之前,恢复预先正确的分区信息。

参考 How to recover a partition accidently deleted with fdisk (Linux)? ,一般可以通过 TestDisk 开源工具修复。

此外,这个案例比较简单,我感觉也可以通过手工方式修复,参考Linux文档的Partition HOWTO 章节 Recovering a Deleted Partition Table ,关键是按照原先分区信息,创建一个 精确一致 的分区表

Partition-Rescue 中介绍了当删除了分区表,但是还没有重启Linux情况下,可以从内核存储的信息

  • 内核存储的分区信息

最主要是知道分区开始的位置

  • 通过 hdparm 工具可以获得详细信息

  • (可选)如果知道一个分区的起始位置,但是不知道结束,仍然可以挂载它,然后了解他的结构。也就是先正确设置分区的起始位置,然后设置一个比原先分区 更大 的任意位置。然后使用以下命令检查推测:

甚至可以挂载然后检查

恢复

根据上述调查,我们可以了解到以下信息

  • 原先的分区表是msdos,被误删除修改成了gpt分区表

  • 由于操作系统还没有重启,所以内核中保留了原先分区的完整信息

    • 一共3个分区,分区信息见上述

  • 再次使用 fdisk /dev/sda 命令,然后执行 o 把分区表改成DOS分区表 ,然后执行 w 保存

  • 然后检查分区表,可以看到分区表已经修改成 dos

  • 现在我们来恢复原先的分区表数据 - 根据之前通过 hdparm -g /dev/sda1 等命令获取的信息

注意到直接按照 hdparm -g /dev/sda1 输出的 sectors = 104853504 值添加分区会导致多一个扇区,所以我们实际添加sectors应该是输出值减1。所以按下 ctrl-c 终止 fdisk 重新添加分区

  • 启动 fdisk 命令,对 /dev/sda 进行分区

输入 p 打印当前分区(目前是空的)

  • 输入 n 命令,添加第一个分区:

  • 输入 p 命令,表示添加主分区 primary,然后两次回车表示默认分区1,以及默认从扇区2048开始第一个分区

  • 现在需要给第一个分区设置大小,我们已经从 hdparm -g /dev/sda1 获得了这个分区的大小是 104853504 扇区。但是由于分区起始扇区是2048,也就是默认已经有了1个sector,所以我们需要添加的sectors数量是原分区sectors数量-1,也就是 +104853503

  • 此时fdisk会检测到之前分区1上有一个ext4文件系统是我们之前已经创建过的文件系统,这个文件系统标记我们不要修改:

  • 这时候提示信息显示分区1包含了ext4标记,实际上就是我们之前旧分区上已经创建过的文件系统,所以我们不需要删除这个标记,输入 N 命令

  • 然后再次输入 p 打印添加了分区1之后的分区情况,验证我们添加的分区是否和原先完全吻合:

请注意,我们输入的 +104853503 之后获得的分区1的扇区数是 104853504 ,和我们从内核获得的原分区扇区数一致,这表明我们添加的分区正确。

  • 重复以上步骤,添加分区2和分区3,同样需要注意sectors添加时数值需要比原分区sectors值减1,最终完成以后的分区表情况如下:

上述分区数据要仔细和 hdparm -g /dev/sdaX 对比(对比 startsectors),例如我们之前获得数据就是

确认无误以后,输入命令 w 保存退出 fdisk

  • 保存退出时会提示信息表示分区表已经修改,但设备繁忙(因为是系统盘正挂载使用中),所以内核依然使用的是旧表。我们通过 fdisk -l 命令再检查一次:

  • 由于文件系统没有重新格式化,所以uuid依然不变,这点可以再次验证

  • 不过blkid显示分区多了一个PARTUUID:

重启验证

比较不幸,重启系统以后,发现系统进入了无盘状态

  • 通过chroot尝试挂载物理服务器磁盘进行检查

挂载以后检查文件系统:

然后检查挂载的文件系统,可以看到文件系统读写都是正常的。这说明之前修复的的磁盘分区是正确的

  • 由于是系统盘,这说明之前 fdisk 破坏的分区表虽然修复正确,但是启动引导信息被抹除以后没有恢复,需要重新修复

  • 通过chroot进入磁盘上的Linux系统

  • 现在使用 df 查看到的操作系统就是完全和从硬盘启动的系统是一致的,除了内核使用的是我们无盘系统的操作系统内核

这里的操作系统是SUSE,可以很容易找到suse的帮助文档,例如 Boot loader repair with grub2 (on OpenSUSE 13.1)Re-install Grub2 from DVD Rescue

  • 在我们这个案例中,/boot/grub2/grub.cfg不需要重新生成(因为之前安装是正确的配置),所以只需要执行 grub2-install 将启动信息写入磁盘就可以:

此时提示:

实际上如果要rescue,在正确挂载了磁盘之后,可以执行2条命令来恢复(如果你安装SUSE过程中安装grub2失败)

  • 再次重启,一切正常了 ^_^

Last updated

Was this helpful?