From 16e2c85922848adb1c21a46a6cc23846ef94b951 Mon Sep 17 00:00:00 2001
From: Guilhem Moulin <guilhem@fripost.org>
Date: Thu, 23 Jan 2014 07:40:58 +0100
Subject: Enable RAID root system.

Quoting /usr/share/doc/cryptsetup/README.keyctl :

    The current state for dm-crypt in Linux is that it is single threaded, thus
    every dm-crypt mapping only uses a single core for crypto operations.  To
    use the full power of your many-core processor it is thus necessary to
    split the dm-crypt device. For Linux software raid arrays the easiest
    segmentation is to just put the dm-crypt layer below the software raid
    layer.

However, this seems no longer true since 2.6.38, cf.

  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=714806
  https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c029772125594e31eb1a5ad9e0913724ed9891f2
  http://kernelnewbies.org/Linux_2_6_38#head-49f5f735853f8cc7c4d89e5c266fe07316b49f4c

Therefore encrypting the array (instead of assembling an array of encrypted
disks) shouldn't cause a performance cost. Also, it makes the ramdisk much
easier to configure :-)
---
 include/partition.sh | 121 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 96 insertions(+), 25 deletions(-)

(limited to 'include')

diff --git a/include/partition.sh b/include/partition.sh
index 5418341..1d5b4c3 100755
--- a/include/partition.sh
+++ b/include/partition.sh
@@ -19,40 +19,111 @@
 set -ue
 
 . /lib/fripost-partman/base.sh
-device=/dev/sda
 
-# Umount existing mountpoints
-for mp in $(sed -nr "s#^$device\S*\s+(\S+).*#\1#p" /proc/mounts); do
-    umount "$mp"
+#device=/dev/sda
+device='/dev/sda /dev/sdb'     # space-separated form mutiple disks (raid)
+raidLevel=1                    # raid level (leave empty for no raid)
+raidActiveDev=2                # number active devices in the array
+
+
+n=0
+for d in $device; do
+    n=$(( $n + 1 ))
+    wait_for_device $d
+
+    # Umount existing mountpoints
+    for mp in $(sed -nr "s#^$d\S*\s+(\S+).*#\1#p" /proc/mounts); do
+        umount "$mp"
+    done
+
+    # Wipe the disk
+    fripost_wipe $d
+
+    # Create a disk label
+    /sbin/parted -s $d mklabel gpt
+    log "Created disklabel GPT for device $d"
+
+    # Don't make an array of these partitions, but keep the alignment
+    # regardless (at the expense of loosing some megabytes)
+
+    # Create a EFI partition if needed; otherwise, create a partition needed
+    # to put GRUB on GPT disklabels.
+    if [ -d /proc/efi -o -d /sys/firmware/efi ]; then
+        size=256M
+        name=efi
+        if [ $n -eq 1 ]; then
+            anna-install dosfstools-udeb
+            part_efi=$( fripost_mkpart $d $name $size +boot )
+            fripost_mkfs vfat $part_efi -F 32
+        else
+            fripost_mkpart $d $name $size
+        fi
+    else
+        size=8M
+        name=bios_grub
+        if [ $n -eq 1 ]; then
+            fripost_mkpart $d $name $size +bios_grub
+        else
+            fripost_mkpart $d $name $size
+        fi
+    fi
 done
 
-# Wipe the disk
-fripost_wipe $device
-
 db_get fripost/encrypt
 encrypt=$RET
 
-# Create a disk label
-/sbin/parted -s $device mklabel gpt
-log "Created disklabel GPT for device $device"
-
-# Create a EFI partition if needed; otherwise, create a partition needed
-# to put GRUB on GPT disklabels.
-if [ -d /proc/efi -o -d /sys/firmware/efi ]; then
-    anna-install dosfstools-udeb
-    part_efi=$( fripost_mkpart $device efi 256M +boot )
-    fripost_mkfs vfat $part_efi -F 32
-else
-    fripost_mkpart $device bios_grub 8M +bios_grub
-fi
-db_set  grub-installer/bootdev $device
+
+# Install GRUB on the first device in case of an array
+db_set  grub-installer/bootdev "${device%% *}"
 db_fset grub-installer/bootdev seen true
 
+part_boot=
+part_system=
 # Create boot and system partitions
-part_boot=$( fripost_mkpart $device boot 64M )
-part_system=$( fripost_mkpart $device system 100% )
-/sbin/parted -s $device align-check opt ${part_system#$device} \
-    || fatal "$part_system is not aligned"
+for d in $device; do
+    pb=$( fripost_mkpart $d boot 64M )
+    ps=$( fripost_mkpart $d system 100% )
+    part_boot="${part_boot:+$part_boot }$pb"
+    part_system="${part_system:+$part_system }$ps"
+    /sbin/parted -s $d align-check opt ${ps#$d} \
+        || fatal "$ps is not aligned"
+done
+
+# Create an array on top of that
+if [ ${raidLevel:-} -a ${raidActiveDev:-} ]; then
+    [ -d /dev/md ] || mkdir /dev/md
+    /sbin/modprobe -v md_mod
+    [ -e /proc/mdstat ] || fail "/proc/mdstat missing"
+
+    log "Creating RAID device /dev/md/boot with $part_boot"
+    mdadm --create /dev/md/boot \
+        -f -R -l raid$raidLevel -n $raidActiveDev \
+        $part_boot
+    part_boot=/dev/md/boot
+    wait_for_device $part_boot
+
+    log "Creating RAID device /dev/md/system with $part_system"
+    mdadm --create /dev/md/system \
+        -f -R -l raid$raidLevel -n $raidActiveDev \
+        $part_system
+    part_system=/dev/md/system
+    wait_for_device $part_system
+
+    # They were only meant to preserve alignment accross physical
+    # devices.
+    log "Remove dummy partitions"
+    for d in ${device#* }; do
+        # efi and bios_grub are only installed on the first disk
+        fripost_rmpart $d efi       || true
+        fripost_rmpart $d bios_grub || true
+    done
+
+    # Note that we're assembling the array *before* encryption rather
+    # than the otherway around. dm_crypt being now multi-threaded, the
+    # order shouldn't impact performances (and that order is
+    # significantly simpler to configure).
+fi
+
 
 
 if [ $encrypt = true ]; then
-- 
cgit v1.2.3