Some days ago I bought a new 500GB Crucial MX500 SSD that was heavily discounted to replace my still perfectly serviceable 128GB Intel 320 Series SSD that stored my Fedora installation. I was running into space problems with some workflows lately, and 500GB is enough for now and allows me to forget about the problem.
One of the things I like to do when migrating to a new computer or hard drive is to keep my Linux installation as it is instead of reinstalling. Sometimes, reinstalling and restoring the most important settings would be faster, but I prefer to keep everything as it is if possible even if it takes a bit longer.
I only had one major problem so this post will serve as documentation for my future self. It’s the first time I did this operation with Fedora.
I plugged my new drive in using a spare SATA cable to have both drives connected at the same time. I created the partition table for the new drive and an ext4 file system covering the whole drive.
When I started using Linux I tried several partitioning schemes like making a specific partition for /home or /var but, while those schemes do have a place in some other contexts, for a simple desktop computer with only one Linux system installed, having a single file system is much simpler and effective, in my opinion. You won’t have to think hard about how much space you’ll need in each partition or face the nightmare of failing to take something into account and having to resize file systems.
If you use a popular file system like ext4 you won’t have to create a separate /boot partition either. In addition, I also avoid creating a swap partition. I use a swap file when needed. I known performance is not as good with it, but it’s much more flexible and, if you start swapping hard, performance is going to suck anyway.
Back to the main subject, when I had the new file system created, I booted from a live SystemRescueCd and mounted both the old and the new file system. Using this live system, in retrospective, has some small risks because, as I will explain later, I need to run some commands after chrooting to the new file system while /dev, /proc and /sys are bind-mounted, and my Fedora installation, including the kernel, could be somewhat incompatible with the running kernel from the live system. I should probably have used a Fedora installation disk instead.
I made sure no hidden files were present in the old root directory and proceeded to run cp -a /old/root/* /new/root. If I had more partitions I would have needed to replicate both structures with additional mounts before running the cp command. cp -a is supposed to preserve every file attribute, including extended attributes and SELinux security labels, I think, but I’ll come back to this later. From this point onwards, every file-related operation I mention in the post refers to the new hard drive.
After copying finished, I edited /etc/fstab and GRUB’s configuration file to replace the old root file system UUID with the new one in both places. If you’re not mounting your Linux file systems by UUID, start doing it now. Then, I bind-mounted (mount --bind) /sys, /proc and /dev on the new file system and chrooted to it from the live CD. I regenerated the initial RAM disk just in case with dracut -f --kver FEDORA_KERNEL_VERSION, where FEDORA_KERNEL_VERSION is the kernel version that was installed on Fedora as the newest kernel, and then rebooted.
I was greeted with a GRUB error message saying it couldn’t find the file system with the old UUID and it dropped me to a console prompt where “help”, “?” and other similar commands where not valid, so it wasn’t of much use to me. I had forgotten to reinstall GRUB and now it was failing to find some files for an early stage before most useful things were ready.
Back to the live CD, I remounted the new file system, bind-mounted again the special file systems and chrooted into it again. This time, I ran grub2-install to reinstall GRUB and, after rebooting, I was finally greeted with GRUB’s menu. Selecting the newest Fedora kernel appeared to boot the system successfully during the first second but happiness didn’t last long as journald was failing to start for some reason and this, in turn, prevented a lot of units from the boot process from working and I couldn’t even get a virtual terminal. The error message was “Failed to start Journal Service”. A web search on that error didn’t spit out many interesting results but, after some time (and I honestly don’t remember exactly how) I realized it could be related to SELinux.
Something had gone wrong while copying files from the live CD between the old drive and the new drive with cp -a and SELinux labels were wrong on the new file system. I don’t know the exact reason and I honestly didn’t have time to investigate, but the quick solution was booting from the live CD again and editing /etc/selinux/config. Merely changing SELinux to disabled or permissive mode allowed me to boot normally into my migrated Fedora installation (yay!). But, if possible, I wanted to keep using SELinux due to the additional security and because in day-to-day operations it never interferes with my workflow. In order to fix labels I left SELinux configured in permissive mode (disabled will not work for the following step) and created an /.autorelabel file.
After rebooting, Fedora sees the file and doesn’t proceed to boot normally. Instead, it changes to a special mode in which SELinux labels are reset to their default values. Then, the autorelabel file is removed and the system reboots. Finally, I changed SELinux to enforcing mode and verified I could still boot normally from the new drive. Success and end of story.
Re-create your file system hierarchy in the new drive.
Mount both hierarchies from a live CD.
Copy files from one hierarchy to the other one with cp -a.
chroot to the new hierarchy mount-binding /proc, /sys and /dev previously.
Edit /etc/fstab and GRUB’s configuration file to mention the new UUIDs.
Regenerate the initial RAM disk for the system kernel just in case.
Change SELinux to permissive mode and create an /.autorelabel file.
Boot into the new drive, wait for SELinux labels to be reapplied and let it reboot.
Verify everything works, then change SELinux to enforcing mode and reboot.
Verify everything continues to work.