spaceflight, technology, anime, politics, and whatever else I feel like writing about

Booting Slackware 15.0 from mdraid under UEFI

Booting directly from software RAID is impossible in most operating systems. This is actually why "motherboard RAID" exists, as a layered storage driver for Windows that presents multiple storage devices as a single drive so that C: can be on mirrored storage. Linux doesn't support motherboard RAID, but Linux mdraid, what you create with mdadm(8), can be booted from, under a few conditions:

  1. the underlying partitions must be flagged as bootable if booting via MBR
  2. the underlying partitions must be flagged as EFI System Partition if booting via EFI
  3. the RAID level must be RAID1, pure mirroring with no striping or erasure coding or other tricks
  4. the mdraid superblock must be at the -end- of the drive

This is of course an incredibly niche setup and you'd probably be better off sticking /boot on a USB stick, but if you need to continue, read on. I have a personal preference for RAID10 over RAID5/RAID6 as providing better I/O and much faster rebuilds, so that's what we're going to be using.

Boot the Slackware 15.0 installer, set your keymap, and log in as root. Don't start the setup program yet, because we have some preparation to do. First, let's look at how many drives we have to work with. Our example system has four SATA drives of identical size and no NVMe.

# ls /dev/sd*
/dev/sda /dev/sdb /dev/sdc /dev/sdd  

Now we'll set up our partition table on /dev/sda with cfdisk.

Partition table: gpt

  • Partition 1: EFI SP, 1GB
  • Partition 2: Linux swap, 4GB
  • Partition 3: Linux, rest of disk

Write the partition table to disk and quit cfdisk.

Now we're going to copy the partition tables to the other disks with sfdisk and a bit of shell scripting.

# for i in {b,c,d} ; do sfdisk -d /dev/sda | sfdisk /dev/sd$i ; done

Now comes actually creating the arrays. First /boot/efi, then swap, then root. The -e 1.0 for /boot/efi is critical since it tells mdadm to put the superblock at the end and thus naive firmware can boot from any of the drives.

# mdadm --create /dev/md0 -e 1.0 --level=1 --raid-devices=4 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1
# mdadm --create /dev/md1 --level=10 --raid-devices=4 /dev/sda2 /dev/sdb2 /dev/sdc2 /dev/sdd2
# mdadm --create /dev/md2 --level=10 --raid-devices=4 /dev/sda3 /dev/sdb3 /dev/sdc3 /dev/sdc3  

Now run setup and install Slackware as usual. Do NOT install LILO or ELILO at this time. Return to the shell once you're done. Now we finish preparing the system to boot. The next step is adding our arrays to mdadm.conf so the initrd can find our arrays when we regenerate it.

# mdadm --detail --scan /dev/md0 >> /mnt/etc/mdadm.conf  
# mdadm --detail --scan /dev/md1 >> /mnt/etc/mdadm.conf  
# mdadm --detail --scan /dev/md2 >> /mnt/etc/mdadm.conf  

This next step will be familiar if you've ever installed Gentoo - we're going to set up a "live chroot" of our newly installed system.

# mount --bind /dev /mnt/dev
# mount --bind /proc /mnt/proc  
# mount --bind /sys /mnt/sys  
# chroot /mnt /bin/bash  

Now we actually create our EFI SP and install ELILO. Feel free to fix the spacing on your fstab later if it bothers you. Skip creating a boot menu entry in eliloconfig.

# mkfs.vfat /dev/md0  
# mkdir -p /boot/efi  
# mount /dev/md0 /boot/efi  
# echo '/dev/md0 /boot/efi vfat defaults 0 0' >> /etc/fstab  
# eliloconfig  

We are not QUITE done. Now we put the huge kernel on our EFI SP to boot from, since it has mdraid support compiled in, make sure elilo set root correctly (expected grep output is included), and regenerate our initrd.

# cp /boot/vmlinuz-huge /boot/efi/EFI/Slackware/vmlinuz  
# grep md2 /boot/efi/EFI/Slackware/elilo.conf
                        append="root=/dev/md2 vga=normal ro"  
# mkinitrd

You should now be able to eject your install media and reboot into your new system.