向左扩展分区后将文件系统向左移动

向左扩展分区后将文件系统向左移动

长话短说

我有一个具有多个分区的dd图像。最终目标是减小该图像文件disk.dd的大小。dd

删除并重新创建一个编号较高的分区start sector offset(即向左扩展分区)后,我有一个分区,其中有一个文件系统,并且该分区primary superblock位于该分区内的某个位置,并且我知道该分区所在的扇区这primary superblock是存在的。

我怎样才能e2fsck将该文件系统移动到分区的开头?

这样之后我就可以用 缩小这个文件系统,resize2fs然后从右边缩小这个分区,即(用较低的值重新创建这个分区end sector offset

dd然后我将对之后的分区重复此过程,直到最后一个分区,有效地缩小所有分区,从而减小图像的大小

请不要建议gparted。我正在寻找命令行解决方案

另外,我知道使用 . 会更容易LVM。但这个遗留系统


长版


disk.dd我有一个使用以下命令拍摄的dd 图像

dd if=/dev/sda of=/path/to/disk.dd

具有以下布局的系统

Disk /dev/loop15: 465.78 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x54093dd5

Device        Boot     Start       End   Sectors   Size Id Type
/dev/loop15p1 *         2048  81922047  81920000  39.1G 83 Linux
/dev/loop15p2       81922048 143362047  61440000  29.3G 82 Linux swap / Solaris
/dev/loop15p3      143362048 163842047  20480000   9.8G 83 Linux
/dev/loop15p4      163842048 976773167 812931120 387.7G  5 Extended
/dev/loop15p5      163844096 976773119 812929024 387.7G 83 Linux

现在,在另一个系统上,我正在disk.dd使用循环设备进行访问

losetup --find --partscan disk.dd

我调整了所有ext4文件系统的大小

resize2fs -M /dev/loopNpartX
resize2fs /dev/loopNpartX FSsize

即分区p1p3p5

使用dumpe2fs,我可以看到logical block size文件系统,它是4096所有ext4文件系统的字节,在我的例子中,如上面所示,托管在 3 个分区上

现在,如果我口头上正确地阅读了这篇文章(如果我错了,请纠正我)

文件系统的主要超级块是“通常预期" 位于0分区块

所以,我可以转储超级块信息

dumpe2fs -h -o superblock=0 -o blocksize=4096 /dev/loopNpartX

现在是时候缩小分区以减小disk.dd文件大小了


block count再次使用每个文件系统dumpe2fs

fdisk适用于设备的physical block sizeOR sectors,在我的例子中是512字节

因此,为了找到sectors足够容纳文件系统的数量,我使用了以下公式

Required Sectors = ( ( Block Count + 100 ) * Logical Block Size ) / Physical Block Size

100充当缓冲区,以防万一我错过了有关文件系统组织的一些内容,这应该足够了

我对每个文件系统都这样做了


现在


使用lsblk -f,我可以获得现有文件系统的 UUID

使用,我可以获取要保持打开状态fdisk -l的分区boot flag

现在要缩小分区,我将删除并重新创建它们fdisk

-- 第一个分区

start sector offset = 2048
last sector offset  = 2048 + "Required Sectors" for this filesystem

-- 第二个分区

现有磁盘上的第二个分区是swap,所以我不会缩小它,只需将其向左移动

start sector offset = "last sector offset" of first partition + 1
last sector offset  = "start sector offset" + Total sectors as as on existing partition

然后我将其类型更改为Swap 然后将tune2fs -UUUID 更改回dd图像上的内容

-- 第三分区

start sector offset = "last sector offset" of second partition + 1
last sector offset  = "start sector offset" + "Required Sectors" for this filesystem

这就是我被困住的地方


向左扩展第三个分区后,该分区有一个文件系统,我知道其起始扇区(即具有 的扇区primary superblock

但我不知道如何e2fsck在分区上纠正该文件系统,以便将文件系统向左移动到分区的开头

答案1

fsck 是不可能的。在文件系统中,一切都有偏移如果你改变起始扇区,所有这些偏移量都会改变。 fsck 根本没有能力重写所有内容(超级块、日志、目录、文件段等)的所有偏移量。即使您可以做到这一点,它也只有在新的起始扇区与内部文件系统结构对齐时才有效。

所以这还没有完成。

相反,您必须使用 dd 将所有数据向左移动(本质上是 gparted 的作用)。只有完全移动文件系统,其中的偏移量才能保持不变。

原则上 dd 命令可以像这样工作。它以不同的偏移量读取和写入同一设备。这只能用于向左移动,所以寻找(写入)必须小于跳过(读自)。 512b 扇区中的所有单元(如果您指定bs=1M,您的分区必须是 MiB 对齐,并且所有单元必须是 MiB 对齐)

dd if=/dev/sdx of=/dev/sdx \
   seek=newpartitionstart \
   skip=oldpartitionstart \
   count=filesystemsize

然而,这是非常危险需要您自担风险使用它。请先花时间备份您的数据。

向右移动会更复杂。您必须向后工作,否则您会覆盖尚未读取的数据,并破坏该过程中的所有内容。


我所知道的唯一能够(或多或少)在不移动数据的情况下完成此操作的工具是blocks --lvmify,它通过将现有文件系统分区转换为 LVM 来实现这一点。使用LVM,您可以在逻辑上向右扩展,而物理上存储在左侧。如果没有 LVM,您还可以手动设置线性设备映射,但随后您就会陷入非标准解决方案。


解决此类问题的最明智的方法(如果您不想使用 gparted)是备份所有数据,然后以您喜欢的任何布局创建新的分区和文件系统,然后恢复数据。

如果此 dd 映像是您的备份解决方案,请考虑改为备份文件。磁盘映像可能很难处理,特别是如果您想随后对其进行转换。


如果您的主要目标是减少映像文件的存储要求,您可以做的是fstrim(for循环安装的文件系统 - 丢失所有可用空间),或blkdiscard(for循环交换分区 - 丢失所有数据)。

如果存储图像的文件系统支持稀疏文件和打孔,那么 dd 图像将使用更少的存储空间而无需更改任何布局,因为图像中的任何可用空间也将被释放给支持文件系统。

同样,这也是危险的,如果丢弃图像文件的错误部分,图像文件就会受到不可恢复的损坏。为图像文件创建循环设备并安装它的简单行为已经修改/损坏了图像文件。

如果源磁盘是 SSD,并且它已经定期使用 fstrim,并将修剪区域读取为二进制 ZERO,那么您可以首先使用 创建一个已经稀疏的 dd 映像dd conv=sparse if=/dev/ssd of=ssd.img。这样任何二进制零区域都不会占用 ssd.img 文件中的空间。请注意,conv=sparse在恢复到非零目标驱动器时,如果用于其他方向,可能会导致结果损坏。

相关内容