TL;博士
我有一个具有多个分区的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
这个文件系统在分区上更正它,以便文件系统向左移动到分区的开头
fsck 是不可能的。在文件系统中,所有东西都有偏移量,如果你改变起始扇区,所有这些偏移量都会改变。fsck 根本无法重写所有内容(超级块、日志、目录、文件段等)的所有偏移量。即使你能做到这一点,它也只有在新的起始扇区与内部文件系统结构一致的情况下才会起作用。
所以这没有完成。
相反,您必须使用 dd 将所有数据向左移动(本质上是 gparted 所做的)。只有完全移动文件系统,其中的偏移量才能保持不变。
原则上 dd 命令可以像这样工作。它以不同的偏移量读取和写入同一设备。这仅适用于向左移动,因此 seek(写入)必须小于skip(读取)。512b 扇区中的所有单元(如果您指定
bs=1M
,则您的分区必须是 MiB 对齐的,并且所有单元都在 MiB 中)但是,这是非常危险的。需要您自担风险使用它。请务必花时间先备份您的数据。
向右移动会更复杂。您必须向后工作,否则您会覆盖尚未读取的数据,并破坏过程中的所有内容。
我所知道的(或多或少)不移动数据的唯一工具是
blocks --lvmify
,它通过将现有文件系统分区转换为 LVM 来实现。使用 LVM,您可以在逻辑上向右扩展,而它在物理上存储在左侧。如果没有 LVM,您也可以手动设置线性设备映射,但您会遇到非标准解决方案。解决此类问题(如果您不想使用 gparted)最明智的方法是备份所有数据,然后以您喜欢的任何布局创建新的分区和文件系统,然后恢复您的数据。
如果此 dd 映像是您的备份解决方案,请考虑改为备份文件。磁盘映像可能很难处理,特别是如果您想在之后转换它们。
如果您的主要目标是减少映像文件的存储需求,您可以做的是
fstrim
(对于循环安装的文件系统 - 丢失所有可用空间),或blkdiscard
(对于循环交换分区 - 丢失所有数据)。如果存储图像的文件系统支持稀疏文件和打孔,它将使 dd 图像使用更少的存储空间而无需更改任何布局,因为图像中的任何可用空间也将被释放用于支持文件系统。
同样,这是危险的,如果您丢弃图像文件的错误部分,图像文件将受到不可恢复的损坏。为图像文件创建循环设备并安装它的简单行为已经修改/损坏了图像文件。
如果源磁盘是 SSD,并且它已经定期使用 fstrim,并且将修剪区域读取为二进制零,那么您可以首先使用
dd conv=sparse if=/dev/ssd of=ssd.img
. 这样,任何二进制零区域都不会占用 ssd.img 文件中的空间。请注意,conv=sparse
在还原到非零目标驱动器时,在其他方向使用时可能会导致损坏的结果。