Migrating whole system from HDD to SSD


Finally I got some time to upgrade my old 2014 Alienware 17 with an SSD.

I'm a lazy guy and do not want to reinstall the Win10/OpenSUSE Leap 42.1 dual boot and customize everything over again. The best option left for me is doing a disk clone. Here's some note about weird problems I ran into which can hardly find any answers with Google.

Clonezilla: The target disk is only one sector smaller than the source.

This is a very weird problem when I tried to clone my 500G HDD to 500G SSD using clonezilla. It gives me an error like below, where the target disk (SSD) is only 1 sector smaller than the source disk (HDD).

Destination Disk is too small!!
Destination Disk Size: 976773118 sectors
Source Disk Size: 976773119 sectors
I tried the trick of choosing the "-icds" option for clonezilla, as stated here, basically it just skips the size check of the target disk while cloning the partition table onto it. However, this doesn't work. After a clueless hour of messing around and staring at this super suspicious 1 sector short in size, I began to think that maybe it is not a problem of the target disk, and maybe it is something wrong with how the computer recognizes the disk and calculates its capacity. And it turns out that when you use a usb-to-sata adapter to connect your SSD to the computer, the usb firmware somehow messed up the counting of sectors. After I attach the disk directly to the sata port onboard, the weird "1 sector smaller" problem is gone.

Copy the btrfs subvolumes

OpenSUSE automatically creates a bunch of subvolumes for mounting a few key directories of the system upon install. You can view these subvolumes with btrfs sub list <your_root_mounting_point>, and get something like below,

ID 257 gen 121 top level 5 path @
ID 258 gen 183144 top level 257 path @/.snapshots
ID 259 gen 183192 top level 258 path @/.snapshots/1/snapshot
ID 260 gen 139403 top level 257 path @/boot/grub2/i386-pc
ID 261 gen 139403 top level 257 path @/boot/grub2/x86_64-efi
ID 262 gen 183147 top level 257 path @/opt
ID 263 gen 139403 top level 257 path @/srv
ID 264 gen 182216 top level 257 path @/tmp
ID 265 gen 182191 top level 257 path @/usr/local
ID 266 gen 182204 top level 257 path @/var/crash
ID 267 gen 139403 top level 257 path @/var/lib/libvirt/images
ID 268 gen 139403 top level 257 path @/var/lib/mailman
ID 269 gen 139403 top level 257 path @/var/lib/mariadb
ID 270 gen 139403 top level 257 path @/var/lib/mysql
ID 271 gen 139403 top level 257 path @/var/lib/named
ID 272 gen 139403 top level 257 path @/var/lib/pgsql
ID 273 gen 182216 top level 257 path @/var/log
ID 274 gen 139403 top level 257 path @/var/opt
ID 275 gen 183197 top level 257 path @/var/spool
ID 276 gen 182216 top level 257 path @/var/tmp
Because I did a disk clone, these subvolumes are now on my SSD. For some directories which may have frequent read/write, like /tmp, /usr/local, /var/log, I want to move them to the HDD. So what I did was:

  • Create readonly snapshot of the subvolume. Here the reason we need readonly snapshot is that later on we will use btrfs send and btrfs receive to copy the subvolume, and they only accept readonly snapshots. I'll only take /tmp as an example here, it's the same routine for other directories.

    $ btrfs sub snap -r /tmp /tmp_bak
    Create a readonly snapshot of '/tmp' in '/tmp_bak'
    

  • Send the snapshot to the target disk, i.e. copy it to my HDD.

    $ btrfs send /tmp_bak | btrfs receive /HDD_mounting_point/
    At subvol /tmp_bak
    At subvol tmp_bak
    

  • Rename the copied snapshot and change it back to read/write snapshot.

    $ btrfs sub snap /HDD_mounting_point/tmp_bak /HDD_mounting_point/tmp
    create a snapshot of '/HDD_mounting_point/tmp_bak' in '/HDD_mounting_point/tmp'
    

  • Delete the intermediate snapshots.

    $ btrfs sub delete /HDD_mounting_point/tmp_bak
    Delete subvolume (no-commit): '/HDD_mounting_point/tmp_bak'
    $ btrfs sub delete /tmp_bak
    Delete subvolume (no-commit): '/tmp_bak'
    

  • Comment out the old mounting entries and add in new mounting entries in /etc/fstab. The new fstab will have something like:

    #UUID=my_ssd_partition_uuid /tmp btrfs subvol=@/tmp 0 0
    UUID=my_hdd_partition_uuid /tmp btrfs subvol=HDD_mounting_point/tmp 0 0
    

By