megi's PinePhone Development Log RSS

2020–09–10: PinePhone multi-boot image deduplication

Btrfs has a nice feature where you can tell it when creating a file to initially use content of some already existing file. This saves space on the filesystem, because the duplicit files can share the same data space without needless data copies. This is almost like hard links, except that data stop being shared, when the file is written.

This can be used in the multi-boot image to save even more space. The multi-distribution image offers many opportunitites for this kind of space saving, due to distributions sharing quite a lot of identical files.

I've written a tool that takes all the rootfs tarballs on input, and goes through all of them, finds duplicities, and calculates space used in total by all files, and space used by unique files. For the current multi-distro image, the numbers look like this:

So the needless overhead of duplicate files accross all included distributions currently is 12.6%, btrfs compression ratio is 50% and the wasted space on the compressed filesystem by the duplicate files is 762 MiB.

That's fairly significant. I can fit another distribution in the wasted space alone. :)

If the included distributions would be much less diverse. For example when including multiple UI variants of postmarket OS, the savings could be even greater. I can potentially add 3 to 4 variants of pmOS if I was able to share duplicate files content, without the current image size changing at all.

I'll try to add FICLONE support to my extraction tool. The tool will basically put content hashes of the files and their paths into a hash table as they are being extracted, and if there's a duplicity, instead of extracting the content of a file, it will use FICLONE to share the data of previously extracted copy of the file.

Resizing the partition after flashing the image

To get more free space when using the multi-image, you can resize it to the full size of your SD card. You can do this from a PC using a SD card reader.

Warning! You'll need to run all the commands as root.

Multi-distro main data partition block device can be found with:

blkid -lt PARTUUID="12345678-02"

For me it prints:

/dev/mmcblk0p2: UUID="0cb50b0b-77a3-45bd-a605-857472b88281" \
   UUID_SUB="a1d75445-1ffe-4e6f-860a-1acdbb4aad2a" \
   BLOCK_SIZE="4096" TYPE="btrfs" PARTUUID="12345678-02"

So for me, btrfs partition is /dev/mmcblk0p2 and the device containing the partition table is /dev/mmcblk0. For you it may be different. Make absolutely sure you're using the correct block device!

Resize the main partition

First, dry run:

echo ", +" | sfdisk -n -N 2 /dev/mmcblk0


Disk /dev/mmcblk0: 29.74 GiB, 31914983424 bytes, 62333952 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: 0x12345678

Old situation:

Device        Boot  Start      End  Sectors  Size Id Type
/dev/mmcblk0p1 *      8192  262143  253952  124M 83 Linux
/dev/mmcblk0p2      262144 15359999 15097856  7.2G 83 Linux

New situation:
Disklabel type: dos
Disk identifier: 0x12345678

Device        Boot  Start      End  Sectors  Size Id Type
/dev/mmcblk0p1 *      8192  262143  253952  124M 83 Linux
/dev/mmcblk0p2      262144 62333951 62071808 29.6G 83 Linux
The partition table is unchanged (--no-act).

Now, verify changes look sane, and do a real resize:

echo ", +" | sfdisk -N 2 /dev/mmcblk0

Resize the main filesystem

Now that the partition is stretched to the end of the SD card, let's resize the contained filesystem too. Btrfs needs to be mounted during resize. The steps thus are:

mount /dev/mmcblk0p2 /mnt
btrfs filesystem resize max /mnt
df -h
umount /mnt

(Make sure when substituting your device for /dev/mmcblk0p2 that you keep the partition number at the end – p2. Thanks to Gazza for pointing out this pitfall.)

You should see:

Resize '/mnt' of 'max'
/dev/mmcblk0p2  30G  6.6G  24G  23% /mnt

And that's all. :)

Forum post

I've posted about my image on the forum. That post contains some additional information: