From 8cf1eceb0a0470311dac60955d72deb1246efdaa Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 6 Feb 2007 16:53:36 +0000 Subject: [PATCH] * Allow multiple file systems to be mounted in stage 1 (i.e., from the initrd). This is useful if /nix (which is necessary for stage 2) is on a different file system than /. svn path=/nixos/trunk/; revision=7862 --- boot/boot-stage-1-init.sh | 100 ++++++++++++++++++++++++++++---------- boot/boot-stage-1.nix | 26 ++++++++-- system/system.nix | 10 ++-- 3 files changed, 99 insertions(+), 37 deletions(-) diff --git a/boot/boot-stage-1-init.sh b/boot/boot-stage-1-init.sh index 9703ac7a8bc7..c57aec960488 100644 --- a/boot/boot-stage-1-init.sh +++ b/boot/boot-stage-1-init.sh @@ -3,6 +3,7 @@ fail() { # If starting stage 2 failed, start an interactive shell. echo "Stage 2 failed, starting emergency shell..." + echo "(Stage 1 init script is $stage2Init)" exec @staticShell@ } @@ -67,12 +68,55 @@ udevtrigger udevsettle +# Function for mounting a file system. +mountFS() { + local device="$1" + local mountPoint="$2" + local options="$3" + + # Check the root device, if . + mustCheck= + if test -b "$device"; then + mustCheck=1 + else + case $device in + LABEL=*) + mustCheck=1 + ;; + esac + fi + + if test -n "$mustCheck"; then + fsck -C -a "$device" + fsckResult=$? + + if test $(($fsckResult | 2)) = $fsckResult; then + echo "fsck finished, rebooting..." + sleep 3 + # reboot -f -d !!! don't have reboot yet + fail + fi + + if test $(($fsckResult | 4)) = $fsckResult; then + echo "$device has unrepaired errors, please fix them manually." + fail + fi + + if test $fsckResult -ge 8; then + echo "fsck on $device failed." + fail + fi + fi + + # Mount read-writable. + mount -n -o "$options" "$device" /mnt/root$mountPoint || fail +} + + # Try to find and mount the root device. mkdir /mnt mkdir /mnt/root -echo "mounting the root device..." - if test -n "@autoDetectRootDevice@"; then # Look for the root device by label. @@ -109,33 +153,37 @@ if test -n "@autoDetectRootDevice@"; then else - # Hard-coded root device. - rootDevice="@rootDevice@" + # Hard-coded root device(s). + mountPoints=(@mountPoints@) + devices=(@devices@) + fsTypes=(@fsTypes@) + optionss=(@optionss@) - # Check the root device. - fsck -C -a "$rootDevice" - fsckResult=$? + for ((n = 0; n < ${#mountPoints[*]}; n++)); do + mountPoint=${mountPoints[$n]} + device=${devices[$n]} + fsType=${fsTypes[$n]} + options=${optionss[$n]} - if test $(($fsckResult | 2)) = $fsckResult; then - echo "fsck finished, rebooting..." - sleep 3 - # reboot -f -d !!! don't have reboot yet - fail - fi + # !!! Really quick hack to support bind mounts, i.e., where + # the "device" should be taken relative to /mnt/root, not /. + # Assume that every device that doesn't start with /dev or + # LABEL= is a bind mount. + case $device in + /dev/*) + ;; + LABEL=*) + ;; + *) + device=/mnt/root$device + ;; + esac - if test $(($fsckResult | 4)) = $fsckResult; then - echo "$rootDevice has unrepaired errors, please fix them manually." - fail - fi - - if test $fsckResult -ge 8; then - echo "fsck on $rootDevice failed." - fail - fi - - # Mount read-writable. - mount -n -o rw "$rootDevice" /mnt/root || fail + echo "mounting $device on $mountPoint..." + mountFS "$device" "$mountPoint" "$options" + done + fi @@ -148,8 +196,6 @@ mount --move . / umount /proc # cleanup umount /sys -echo "INIT = $stage2Init" - if test -z "$stage2Init"; then fail; fi exec chroot . $stage2Init diff --git a/boot/boot-stage-1.nix b/boot/boot-stage-1.nix index 8a21d87bf610..49c53e1ed728 100644 --- a/boot/boot-stage-1.nix +++ b/boot/boot-stage-1.nix @@ -10,8 +10,15 @@ , # Whether to find root device automatically using its label. autoDetectRootDevice -, # If not scanning, the root must be specified explicitly. - rootDevice +, # If not scanning, the root must be specified explicitly. Actually, + # stage 1 can mount multiple file systems. This is necessary if, + # for instance, /nix (necessary for stage 2) is on a different file + # system than /. + # + # This is a list of {mountPoint, device|label} attribute sets, i.e., + # the format used by the fileSystems configuration option. There + # must at least be a file system for the / mount point in this list. + fileSystems ? [] # If scanning, we need a disk label. , rootLabel @@ -21,12 +28,23 @@ stage2Init ? "/init" }: +let + + # !!! use XML; copy&pasted from upstart-jobs/filesystems.nix. + mountPoints = map (fs: fs.mountPoint) fileSystems; + devices = map (fs: if fs ? device then fs.device else "LABEL=" + fs.label) fileSystems; + fsTypes = map (fs: if fs ? fsType then fs.fsType else "auto") fileSystems; + optionss = map (fs: if fs ? options then fs.options else "defaults") fileSystems; + +in + +assert autoDetectRootDevice -> mountPoints != []; + substituteAll { src = ./boot-stage-1-init.sh; isExecutable = true; inherit staticShell modules modulesDir; - inherit autoDetectRootDevice; - rootDevice = if !autoDetectRootDevice then rootDevice else ""; + inherit autoDetectRootDevice mountPoints devices fsTypes optionss; rootLabel = if autoDetectRootDevice then rootLabel else ""; path = [ staticTools diff --git a/system/system.nix b/system/system.nix index b3a888e65908..c29d6100c986 100644 --- a/system/system.nix +++ b/system/system.nix @@ -68,12 +68,10 @@ rec { inherit (pkgsDiet) module_init_tools; inherit extraUtils; autoDetectRootDevice = config.get ["boot" "autoDetectRootDevice"]; - rootDevice = - let rootFS = - (pkgs.library.findSingle (fs: fs.mountPoint == "/") - (abort "No root mount point declared.") - (config.get ["fileSystems"])); - in if rootFS ? device then rootFS.device else "LABEL=" + rootFS.label; + fileSystems = + pkgs.lib.filter + (fs: fs.mountPoint == "/" || (fs ? neededForBoot && fs.neededForBoot)) + (config.get ["fileSystems"]); rootLabel = config.get ["boot" "rootLabel"]; inherit stage2Init; modulesDir = modulesClosure;