How do I shrink the partition of an img file made from dd?

Solution 1:

On loop images

First of all, forget offset=, use losetup --partscan and just mount the partition via /dev/loop0p1.

# losetup --partscan /dev/loop0 myimage.img
# lsblk
# mount /dev/loop0p1 /mnt

To efficiently clear empty space within a partition, run fstrim on the loop-mounted filesystem, just like you would on an SSD. (This will actually make the image file sparse.)

# fstrim -v /mnt

On resizing partitions

But for now, you don't need to clear empty space or do anything like that. Whether the about-to-be-truncated area is filled with zeros or with chunks of old data is completely irrelevant.

Instead, you need to do exactly the same as you would do with ext4 on a real disk – you need to shrink each layer from the inside out. You cannot skip steps just because it's an image.

To shrink a partition that contains a filesystem, you must first tell the filesystem to shrink itself. For ext2/3/4 this is done using resize2fs. This will relocate data that might be living in the area you're about to chop off, and will store the new boundaries as part of the filesystem's metadata. (I suppose that's what you meant by "defragmenting" it.)

Only once the filesystem has been shrunk you can also shrink the partition containing it. This can be done via parted or fdisk by just changing the partition's end address.

Side note: You should be able to use GParted to resize the filesystem and the partition in one step – if it supports with working on loop devices, that is. It might depend on GParted's version. (However, the CLI parted cannot shrink filesystems, it just truncates the partition.)

Finally, once both the filesystem and the partition have been resized, you can truncate the whole image containing them. To do that, first detach the loop device and use truncate --size=... on your image file.

(To do it safely without having to do careful calculations, I would shrink the filesystem slightly more than needed to create some 'buffer' space; e.g. if I wanted a 4 GB image, I'd shrink the filesystem to 3 GB, the partition to 3.5 GB, and then truncate the image to 4 GB. Then grow everything in the opposite order to fill the 'buffer' space.)