Root file system on software RAID-0 THE EASY WAY

Author: David Flater, dave@flaterco.com
URL: http://www.flaterco.com/kb/RAID-0-root.html
Last modified: Wed Feb 13 22:24:19 EST 2008

Introduction

There are plenty of web pages giving complicated instructions for how to get a striped RAID-0 file system mounted as your root file system in Linux.  They say you have to create an initrd or initramfs with /dev files and /lib files and a linuxrc script that loads kernel modules and mounts /proc and whatnot so that it can finally assemble the RAID array and start the real boot process.  But you don't need to do any of that!

How-To

If you boot a kernel with RAID and the other necessary drivers built in (NOT as modules), it will automatically assemble partitions of type fd ("Linux raid autodetect") into a RAID array that you can use as your root fs.

The only slightly tricky thing is that the kernel itself cannot be loaded from the RAID array.  All you need to get around that is a small, non-RAID partition that is just big enough to hold the stuff that normally goes in /boot (the kernel, System.map, config, and a few LILO files), and a correct LILO configuration.

Following is what I did to get this working using a Slackware 12.0-based installation CD.

  1. Replaced the Slackware kernel package with my own build of mainline kernel 2.6.24.2 in which most things are built in.  Only certain things (like ALSA) need to be modules.  Slackware's own huge.s kernel would probably work too.
  2. At the root prompt after booting from the CD, partitioned the two hard disks as follows.  /dev/hde was larger than /dev/hdg, but I partitioned them so that the RAID-0 partitions would be the same size or as close as I could get them to be.
    Disk /dev/hde: 20.5 GB, 20525137920 bytes
    16 heads, 63 sectors/track, 39770 cylinders
    Units = cylinders of 1008 * 512 = 516096 bytes
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/hde1               1        5925     2986168+   c  W95 FAT32 (LBA)  # Reserved for Windows 98 SE + DOOM 95
    /dev/hde2            5926        6025       50400    e  W95 FAT16 (LBA)  # Reserved for DOS + DOOM 1.9
    /dev/hde3            6026        6035        5040   83  Linux            # /boot
    /dev/hde4            6036       39770    17002440    5  Extended
    /dev/hde5            6036        6229       97744+  82  Linux swap
    /dev/hde6            6230       39770    16904632+  fd  Linux raid autodetect
    
    Disk /dev/hdg: 17.4 GB, 17410498560 bytes
    16 heads, 63 sectors/track, 33735 cylinders
    Units = cylinders of 1008 * 512 = 516096 bytes
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/hdg1               1         194       97744+  82  Linux swap
    /dev/hdg2             195       33735    16904664   fd  Linux raid autodetect
    
  3. Still at the root prompt, created the RAID array:
    mdadm -C /dev/md0 -l 0 -n 2 /dev/hde6 /dev/hdg2
    
  4. Started Slackware setup.
  5. Specified /dev/md0 as the root file system and formatted it.
  6. Formatted /dev/hde3 and mounted it on /boot.
  7. Ran through the Slackware install process as usual, allowing it to drop the kernel into /boot but skipping the LILO install.  This left /dev/md0 mounted on /mnt and /dev/hde3 mounted on /mnt/boot.
  8. After exiting Slackware setup, went into /mnt/etc and created the following lilo.conf:
    boot = /dev/hde       # LILO goes in the MBR.
    compact               # Boot fast,
    vga = normal          # and skip the foo-foo.
    
    # /dev/hde3 is mounted as /boot, so /boot/vmlinuz is on the non-RAIDed
    # partition /dev/hde3.
    image = /boot/vmlinuz
      # The kernel will automatically assemble the partitions of type fd
      # into a RAID array on /dev/md0.  Use that as the root file system.
      append = "root=/dev/md0"
      label = linux
      read-only
    
  9. Did lilo -r /mnt to install LILO.
  10. Unmounted everything and rebooted.

Notes

  1. The RAID used here was Linux's own software RAID, which always works.  It did not involve the BIOS of a modern "fakeraid" motherboard or anything else.  The hard drives were connected to a Promise Ultra66 PCI IDE controller card with no RAID support.
  2. Booting RAID-1 (mirrored not striped) is not a challenge.  LILO can boot the kernel directly from any device in the array.  RAID-0 is a challenge because a kernel stored within the RAID array would get split across the multiple devices, and LILO needs it in one piece to boot it.
  3. /dev/mdN is used for a non-partitionable array.  A partitionable array would use /dev/md_dN or /dev/md/dN instead.  See the DEVICE NAMES section at the bottom of the mdadm man page.
  4. As of 2008-02-12, the web page http://linux-raid.osdl.org/index.php/RAID_Boot describes the kernel RAID autodetect feature as "deprecated."  IMHO, you should not deprecate a feature unless and until an alternative with comparable functionality and usability is available.  The initramfs approach is vastly more complicated and error-prone, so it's not a credible replacement.

Log messages

Linux version 2.6.24.2 (root@yellowbeard) (gcc version 4.2.1) #2 Wed Feb 13 09:59:00 EST 2008

PDC20262: IDE controller (0x105a:0x4d38 rev 0x01) at  PCI slot 0000:00:0c.0
PCI: setting IRQ 11 as level-triggered
PCI: Found IRQ 11 for device 0000:00:0c.0
PDC20262: 100% native mode on irq 11
PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
    ide2: BM-DMA at 0xb800-0xb807, BIOS settings: hde:DMA, hdf:DMA
    ide3: BM-DMA at 0xb808-0xb80f, BIOS settings: hdg:DMA, hdh:pio
Probing IDE interface ide2...
hde: IBM-DPTA-372050, ATA DISK drive
hde: host max PIO4 wanted PIO255(auto-tune) selected PIO4
hde: UDMA/66 mode selected
ide2 at 0xe000-0xe007,0xd802 on irq 11
Probing IDE interface ide3...
hdg: Maxtor 91741U4, ATA DISK drive
hdg: host max PIO4 wanted PIO255(auto-tune) selected PIO4
hdg: UDMA/66 mode selected
ide3 at 0xd400-0xd407,0xd002 on irq 11

hde: max request size: 128KiB
hde: 40088160 sectors (20525 MB) w/1961KiB Cache, CHS=39770/16/63
hde: cache flushes not supported
 hde: hde1 hde2 hde3 hde4 < hde5 hde6 >
hdg: max request size: 128KiB
hdg: 34004880 sectors (17410 MB) w/512KiB Cache, CHS=33735/16/63
hdg: cache flushes not supported
 hdg: hdg1 hdg2

md: Autodetecting RAID arrays.
md: Scanned 2 and added 2 devices.
md: autorun ...
md: considering hdg2 ...
md:  adding hdg2 ...
md:  adding hde6 ...
md: created md0
md: bind
md: bind
md: running: 
md0: setting max_sectors to 128, segment boundary to 32767
raid0: looking at hdg2
raid0:   comparing hdg2(16904576) with hdg2(16904576)
raid0:   END
raid0:   ==> UNIQUE
raid0: 1 zones
raid0: looking at hde6
raid0:   comparing hde6(16904512) with hdg2(16904576)
raid0:   NOT EQUAL
raid0:   comparing hde6(16904512) with hde6(16904512)
raid0:   END
raid0:   ==> UNIQUE
raid0: 2 zones
raid0: FINAL 2 zones
raid0: zone 1
raid0: checking hde6 ... nope.
raid0: checking hdg2 ... contained as device 0
  (16904576) is smallest!.
raid0: zone->nb_dev: 1, size: 64
raid0: current zone offset: 16904576
raid0: done.
raid0 : md_size is 33809088 blocks.
raid0 : conf->hash_spacing is 33809024 blocks.
raid0 : nb_zone is 2.
raid0 : Allocating 8 bytes for hash.
md: ... autorun DONE.
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 280k freed
Adding 97736k swap on /dev/hde5.  Priority:-1 extents:1 across:97736k
Adding 97736k swap on /dev/hdg1.  Priority:-2 extents:1 across:97736k
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/md/0             33278448   1719380  29868616   6% /
/dev/hde3                 4877      2761      1864  60% /boot

KB
Home