When you back up a sd card and attempt to flash the image to a second card, it can happen that you will be greeted by the message "Too small". This can happen because two sd cards from even the same vendor could have slightly different sizes.
In this tutorial, I will show you how to shrink an image to a specific size, so it can fit on a smaller sd card.
But be aware: You will also need a little bit of math for this one.
At first, backup the sd card to an image with dd
to a file called my-image.img
.
sudo dd if=/dev/sda of="my-image.img" bs=1M status=progress
If you are not sure which device is the correct one, list them by running sudo fdisk -l
.
Now create a pseudo-device wit the help of losetup
so the image is mountable.
sudo losetup --show -f -P my-image.img
The image is now available under /dev/loop0
.
Before resizing the file system, run a file system check on the partition you want to resize.
As I want to resize the second partition, I need to pass /dev/loop0p2
as device. You can check for the correct device
by running sudo fdisk -l /dev/loop0
.
sudo e2fsck -f /dev/loop0p2
While a partition is a logically independent section of a physical storage device, a file system is a method or structure
used to organize and store data on a storage device. The file system will be created in a partition which sets the start
and end.
Since we want to shrink the file system and partition, we must first shrink the file system before shrinking the partition.
If you want to expand the file system and partition, it would be the other way around: First partition, then file system.
By running following command, the file system on /dev/loop0p2
will be resized to 5 gigabytes.
sudo resize2fs /dev/loop0p2 5G
Since resizepart of parted works different, we need to do a little bit of math since resizepart takes the end of the partition as parameter and not its target size.
First, we need to get the size of the partition in bytes by multiplying the block count by the block size.
# Command
sudo tune2fs -l /dev/loop0p2 | grep 'Block count\|Block size'
# Output:
Block count: 1310720
Block size: 4096
Now multiply the block count by the block size:
1310720 blocks * 4096 bytes = 5368709120 bytes
Now we need to get the start sector of our partition.
Please notice the string p2
in grep which stands again for the second partition.
# Input
sudo fdisk -l /dev/loop0 | grep 'p2\|Sector size\|Device'
# Output
Sector size (logical/physical): 512 bytes / 512 bytes
Device Boot Start End Sectors Size Id Type
/dev/loop0p2 532480 62333951 61801472 29.5G 83 Linux
Since we need the new end position of the partition as sector, we need to divide the result of block size * block count
through the sector size.
Size in bytes / Sector size = sectors
5368709120 bytes / 512 bytes sector size = 10485760 sectors
Afterward, add the result to the start sector and subtract 1.
Sectors + Start - 1 = End sector new
10485760 + 532480 - 1 = 11018239
Now finally resize the partition:
sudo parted /dev/loop0 unit s resizepart 2 11018239
Remove the pseudo-device since we do not need it anymore.
sudo losetup -D my-image.img
Now we need to get some information about the partition layout, sectors and the block size by running fdisk
.
# Input
sudo fdisk -l my-image.img
# Output
Disk my-image.img: 29.72 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: 0xb438c57d
Device Boot Start End Sectors Size Id Type
my-image.img1 8192 532479 524288 256M c W95 FAT32 (LBA)
my-image.img2 532480 11018239 10485760 5G 83 Linux
Take a closed look at the partition table type labeled as Disklabel type
.
While Raspberry PIs use the Master Boot Record
as partition table labeled DOS
, Radxa boards for example use the
GUID Partition Table
labeled as GPT
. This is important because the GPT
backups the table at the end of the disk.
If we cut of the end of the disk image handled by GPT, we need to add some space to re-add it again by adding at least
16.384 bytes of empty space.
(End sector + 1) * Sector size = truncate length
(11018239 + 1) * 512 = 5641338880 sectors
Now, truncate the image...
sudo truncate -s 5641338880 my-image.img
... and flash it to the new sd card.
sudo dd if=my-image.img of=/dev/sda bs=1M status=progress
The GPT
needs a minimum length of 16.384 bytes. So the amount of sectors which needs to be added at the end relies on
the sector size.
Sector size 512 bytes -> 16,384/512 = 32 sectors
Sector size 4.096 bytes -> 16.384/4.096 = 4 sectors
Since I have a sector size of 512 bytes
(see 4.), I need to add a minimum of 4 sectors plus additionally 1 because
sectors start at 1 and not at 0.
Since the truncate command takes the amount of bytes as argument, multiply the count of sectors by the sector size.
(last END + 4 + 1) * sector size = truncate_length
(11018239 + 4 + 1) * 512 = 5.641.340.928 bytes
Now run truncate with the target length
truncate -s 5641340928 my-image.img
and fix the GPT
of the disk image by running gdisk
.
sudo gdisk my-image.img
Now flash the image to the new sd card.
sudo dd if=my-image.img of=/dev/sda bs=1M status=progress
Afterward, move the backup GPT to the end of the disk, where it belongs.
sgdisk --move-second-header /dev/sda
That's it. Now you can boot from the newly created SD card.