Migrating Raspberry Pi to new SSD
Since setting up my Raspberry Pi to boot from a USB SSD, I need to repurpose the SSD I used to set this up. I bought a smaller 240GB SSD to replace it and wanted to copy the existing filesystem over to it rather than reinstall.
Partitioning
First thing I did was to partition the new disk. The existing (512GB) disk has 2 partitions - ~300MB for the boot loader (mounted at /boot/firmware
) and the rest as one large root partition. I did not, when I set this up, modify the default Raspbian setup to give it a swap partition which with hindsight was an error for 2 reasons:
- My Raspberry Pi 4 only has 2GB of memory, which most of the time is plenty (as I write this, 275MB is currently used) but a burst in need could cause it to run out
- My icinga2 monitoring system expects swap and flags systems with no swap as in an error state. I could silence this but since I am adding a huge SSD with far more capacity than is required, it would be easier to just add it now.
I therefore replicated the existing boot partition, added a 10G swap partition and then created the same single large partition on the new disk. I am uncomfortable with the single large partition, splitting data between partitions has been a long established practice on Linux systems to help mitigate the impact of a filesystem being filled by runaway processes, or otherwise, accidentally on the stability (and ability to login!) of the whole system.
Launching sfdisk, I then issued the commands to create a 299M FAT32 (type c
) partition (matching precisely what is on the existing disk), an 10G Linux Swap (type 82
) partition and the rest of the space for Linux Data (type 83
):
>>> ,299M,c
Created a new DOS disklabel with disk identifier 0xeb82491d.
Created a new partition 1 of type 'W95 FAT32 (LBA)' and of size 299 MiB.
/dev/sdb1 : 2048 614399 (299M) W95 FAT32 (LBA)
Created a new partition 2 of type 'Linux swap / Solaris' and of size 10 GiB.
/dev/sdb2 : 614400 21585919 (10G) Linux swap / Solaris
/dev/sdb3: ,,83
Created a new partition 3 of type 'Linux' and of size 213.3 GiB.
/dev/sdb3 : 21585920 468862127 (213.3G) Linux
/dev/sdb4: write
New situation:
Disklabel type: dos
Disk identifier: 0xa2e77eb5
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 614399 612352 299M c W95 FAT32 (LBA)
/dev/sdb2 614400 21585919 20971520 10G 82 Linux swap / Solaris
/dev/sdb3 21585920 468862127 447276208 213.3G 83 Linux
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Copying the boot loader
As the source and destinations partitions are exactly the same size, I simply unmounted the old partition and used dd
to copy one to the other:
# umount /boot/firmware
# dd if=/dev/sda1 of=/dev/sdb1 bs=1M
299+0 records in
299+0 records out
313524224 bytes (314 MB, 299 MiB) copied, 9.8722 s, 31.8 MB/s
# mount /dev/sdb1 /boot/firmware
# vim /boot/firmware/cmdline.txt # Modify root=/dev/sda2 to root=/dev/sda3
# umount /boot/firmware
Copying the rest of the system
For the rest of the system, I choose to stop the monitoring daemons and then simply rsync the entire filesystem over. Despite my unease with it, this is actually made easier by having the whole system in a single large root
partition as rather than excluding /dev
, /sys
, /proc
, /run
etc. by hand I just told rsync not to cross filesystem-boundaries.
Firstly, stopping the daemons:
# systemctl stop icinga2
# systemctl stop munin-node
# systemctl stop munin
Create and mount the new filesystem (N.B. the RASPIROOT
label is important as that is what is used in FSTAB to mount the root partition):
# mkfs.ext4 -L RASPIROOT /dev/sdb3
mke2fs 1.44.5 (15-Dec-2018)
Creating filesystem with 55909526 4k blocks and 13983744 inodes
Filesystem UUID: 8f1623cc-032c-4e88-b025-c8092cfa32a2
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
# mkdir /mnt/newroot
# mount /dev/sdb3 /mnt/newroot
Do the copy:
# rsync -aHAXxvP / /mnt/newroot/
The options in use are:
-a
- archive (equivalent to-rlptgoD
)-H
- preserve hard-links-A
- copy acls (I’m not sure there are any on this system but better to be safe…)-X
- copy extended attributes-x
- do not cross filesystem boundaries (just copy the root filesystem)-v
- verbose-P
- equivalent to--partial --progress
, resume partition copies (if the copy gets interrupted) and show progress during transfer
During my first attempt to copy, the Pi hung and had to be rebooted (pull and plug the power) but the 2nd time it copied everything without any drama.
I repeated the copy to ensure nothing had been missed - only log files (which I would have expected to change) were copied in this “catch up” copy.
Booting into the new system
Next I powered off the Pi, swapped the disks over and booted off the new disk.
Setting up swap
Finally, I needed to setup that new swap partition.
# mkswap -L RASPISWAP /dev/sda2
Setting up swapspace version 1, size = 10 GiB (10737414144 bytes)
LABEL=RASPISWAP, UUID=806e1fc8-9eb5-445c-b0b9-a5382238290f
# echo "LABEL=RASPISWAP none swap sw 0 0" >> /etc/fstab
# swapon -a
# cat /proc/swaps
And for good measure, rebooted to ensure the swap partition continues to be picked up afterwards (it did).