长话短说
我有一个具有多个分区的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
即分区p1
,p3
和p5
使用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 size
OR 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 -U
UUID 更改回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
在恢复到非零目标驱动器时,如果用于其他方向,可能会导致结果损坏。