Move linux root partition to another disk

May 3, 2016

Context: Almost 3 years ago, I bought a Latitude E7440 laptop from Dell to replace my old eeePC. As shipped, it featured a 500Go HDD and an empty mSATA port that I quickly filled with a SSD. Back in the time, to avoid EFI issues, I dedicated the full SSD to Windows. But now that I almost only use Fedora, I looked into how to migrate my linux partition from the HDD to the SSD.


DISCLAIMER Moving partition around is kind of risky. In the worst case the whole disk’s data can become unusable. Ensure that you backed-up all your data and always think twice before you hit ENTER .

This case

This process can be time consuming - it took me something like 10 or 12h overall. Think bout doing a fresh install cannot do the job before starting anything ;)

Partition state and target

Tools that you can use : fdisk -l /dev/[id], lsblk, blkid.

Here is the layout before any changes

$> lsblk
  sda      8:0    0 465,8G  0 disk             # 500Go HDD
  ├─sda1   8:1    0   200M  0 part /boot/efi   # . Linux EFI boot partition
  ├─sda2   8:2    0   500M  0 part /boot       # . Linux kernel and images
  ├─sda3   8:3    0    50G  0 part /           # . Linux root filesystem
  ├─sda4   8:4    0   7,8G  0 part [SWAP]
  ├─sda5   8:5    0  97,7G  0 part /home       # . Linux /home
  └─sda6   8:6    0 309,7G  0 part /STK        # . Shared NTFS storage

  sdb      8:16   0 232,9G  0 disk             # 250Go SSD
  ├─sdb1   8:17   0   300M  0 part             # . Windows emergency boot
  ├─sdb2   8:18   0    99M  0 part             # . Windows EFI boot
  ├─sdb3   8:19   0   128M  0 part             # . Windows stuff
  ├─sdb4   8:20   0 231,9G  0 part             # . Windows to shrink 
  └─sdb5   8:21   0   450M  0 part             # . Diag partition


The goal is to merge / and /home into a new partiton on the SSD by shrinking sdb4.

Prepare the filesystems

1. Shrink the windows partition

Windows can do that with the disk manager, but sometime unmovable files got in the way. Better use gparted, worked flawlessly. When you’re done, use the empty space to create an new ext4 partition. It should look like that:

sdb      8:16   0 232,9G  0 disk
├─sdb1   8:17   0   300M  0 part
├─sdb2   8:18   0    99M  0 part
├─sdb3   8:19   0   128M  0 part
├─sdb4   8:20   0  88,6G  0 part # Shrinked Windows
├─sdb5   8:21   0   450M  0 part
└─sdb6   8:22   0 143,3G  0 part # New partition !

2. Copy / and /home to the new partition

Grab wathever live linux you have and boot it (mine was Xubuntu 14.04). Mount you old / and the new one. Now you can cp or rsync the content from one to the other. Here is an example from the Archlinux wiki; don’t forget to change the --exclude to match the path of the old root!

rsync -aAXS --info=progress2 --exclude={"/old/root/lost+found"} /old/root /path/to/new/root

Do the same for the old /home to /new/root/home if necessary.

3. Edit mount file of the new partition

Before you can use the new partion, you need to edit /new/root/etc/fstab to match the new mountpoint. Use either UUID (that you can get with blkid as root) or direct mountpoints.

Now that we have a nice copy of the root partition on the SSD, let’s boot it!

Getting it to boot

Uderstanding the boot process

The boot process of a computer is not something you’re supposed to go into every morning…

I read a loot of stuff all other the Internet before I figured it, and this page is a nice sum-up of all the things you need to know.

tl;dr (only for EFI-GPT systems)

  1. BIOS look for an EFI tagged partition
  2. EFI firmware run whatever is in /boot/efi, here the GRUB2 manager
  3. GRUB2 use the file located at boot/efi/EFI/fedora/grub.cfg to configure startup enties
  4. This file can be generated using grub2-mkconfig as described in the fedora doc
  5. Each startup entry give the location of the kernel to run and root filesystem target

Here’s mine (expurged for clarity):

menuentry 'Fedora (4.5.2-302.fc24.x86_64) 24 (Workstation Edition)' {
    set gfxpayload=keep
    insmod gzio
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  [UUID]
      search --no-floppy --fs-uuid --set=root [UUID]
    linuxefi /vmlinuz-4.5.2-302.fc24.x86_64 root=UUID=[UUID] ro vconsole.font=latarcyrheb-sun16  rhgb quiet
    initrdefi /initramfs-4.5.2-302.fc24.x86_64.img

Booting up

Run as root:

$> grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

GRUB2 will look into all the partitions and try to build a file by auto-detecting OSs. Now if you reboot, you should have a new entry to boot the new / alongside the old one.

At this point, theorically, we should be able to boot the new / partition - sbd6 in my case using the same /boot and /boot/efi as before (still on HDD).

But in real-life, the new startup entry is not working at all, giving us two errors:

error: can't find `linux`
error: can't find `initrd`

Nobody’s perfect

If you select the old startup entry, you can still boot on the HDD, therefor the issue lays into grub.cfg.

Let’s take a close look at the generated startup entry:

menuentry 'Fedora (4.4.7-300.fc23.x86_64) 24 (Workstation Edition) (on /dev/sdb6)' {
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 [UUID]
      search --no-floppy --fs-uuid --set=root [UUID]
    linux /vmlinuz-4.4.7-300.fc23.x86_64 root=/dev/sda3 ro vconsole.font=latarcyrheb-sun16 rhgb quiet
    initrd /initramfs-4.4.7-300.fc23.x86_64.img

If you have sharp eyes and compare it with the previous one, you can spot several differences:

  • some insmod are missing
  • kernel is started using linux instead of linuxefi, same thing for initrd
  • the root filesystem passed to the kernel is sda3 (old HDD /) instead of sdb6

Let’s fix that!

menuentry 'Fedora (4.5.2-302.fc24.x86_64) 24 (Workstation Edition) (on /dev/sdb6)' {
    set gfxpayload=keep
    insmod gzio
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 [BOOT UUID]
      search --no-floppy --fs-uuid --set=root [BOOT UUID]
    linuxefi /vmlinuz-4.5.2-302.fc24.x86_64 root=UUID=[sdb6 UUID] ro vconsole.font=latarcyrheb-sun16 rhgb quiet
    initrdefi /initramfs-4.5.2-302.fc24.x86_64.img

Now reboot and enjoy the modern world!