Monday, November 13, 2023

Shrinking a Raspberry Pi Image

Flash memory prices crashed in 2023, so it is getting hard to find low-capacity microSD cards. However, when you install Raspberry Pi OS on a new microSD card, one of the first things it does is resize the root partition to use the entire card. This is fine since it gives you space to play around with. However, when it's time to back up your system or make an image for cloning, you might end up with a giant, mostly empty image file. This post describes how to shrink it back down to a more convenient size.

The Process

Take the microSD card from you Pi and connect it to some other Linux machine. Assume it shows up as /dev/sdb and has two partitions, where the first is /boot and the second is the root filesystem. First, you can use the df command to see how many blocks are used:

$ df

Or use df -h to get the size in more directly useful units. You're interested in the value for /dev/sdb2 in the "Used" column.

Then, you'll probably need to unmount it:

$ sudo umount /dev/sdb1 /dev/sdb2

Next, you will resize the filesystem. First, check the filesystem for errors:

$ sudo e2fsck -f /dev/sdb2

Then, resize it to something a little bigger than the used space reported by du. For example, to make it 3GB, use this command:

$ sudo resize2fs /dev/sdb2 3G

When this command completes, it will tell you how many 4k blocks the filesystem now occupies. Multiply this number by 8 to get the number of 512-byte disk blocks.

Next, run fdisk

$ sudo fdisk /dev/sdb

Print the current partition table (p), delete the rootfs partition (d) and add it back (n). When it asks you for the new first sector, use the value from the original partition. For the last sector, type "+" followed by the number of disk blocks you calculated above. For example, to match the 3G partition above, which is 786432 4k blocks long, you'd type +6291456.

If asked whether you want to clear the ext4 signature, you can say no since you don't want to modify the partition.

Print the new partition table (p), then write the new partition table and exit (w).

To create an image file, you can use dd:

$ sudo dd bs=512 if=/dev/sdb of=sdcard.img count=6823936

Where the value after count= is the "End" sector number of the last partition shown when you printed out the new partition table.

This will give you a much more compact image file that can go onto any microSD card you happen to have laying around, leaving the unused space blank.

If you later want to re-expand it to fill the entire microSD card, then when you boot your Raspberry Pi, you can run the command:

$ sudo raspi-config nonint do_expand_rootfs

Then reboot. 

Note that this requires a read/write filesystem. If you have a read-only filesystem, you'll have to mount read/write and run resize2fs yourself.