* Use mountall to mount all filesystems and activate all swap devices

during boot.  Mountall ensures that these are done in the right
  order.  It's informed by udev about devices becoming available.  It
  emits some Upstart events upon reaching certain states, in
  particular ‘local-filesystems’ after all local filesystems have been
  mounted successfully, ‘remote-filesystems’ after all network
  filesystems have been mounted, and ‘filesystem’ (sic) when all
  filesystems have been mounted.

  Currently, if a filesystem fails to mount or doesn't exist, then the
  mingettys won't start and the boot will appear to hang.  This is
  because mountall doesn't emit an event for failing filesystems and
  waits indefinitely for the filesystems to become available.

* The ‘filesystems’ and ‘swap’ Upstart jobs are gone.  (Support for
  encrypted swap devices is temporarily gone.)
  
* Generate a proper /etc/fstab from the ‘fileSystems’ and
  ‘swapDevices’ options.

svn path=/nixos/branches/boot-order/; revision=22148
This commit is contained in:
Eelco Dolstra 2010-06-04 14:22:11 +00:00
parent 5316059442
commit dbadf6e9c2
3 changed files with 45 additions and 174 deletions

View file

@ -55,7 +55,7 @@ with pkgs.lib;
# Generate a separate job for each tty.
jobs = listToAttrs (map (tty: nameValuePair tty {
startOn = "started udev";
startOn = "started udev and local-filesystems";
exec = "${pkgs.mingetty}/sbin/mingetty --loginprog=${pkgs.shadow}/bin/login --noclear ${tty}";

View file

@ -2,108 +2,6 @@
with pkgs.lib;
let
fileSystems = config.fileSystems;
mount = config.system.sbin.mount;
task =
''
PATH=${pkgs.e2fsprogs}/sbin:${pkgs.utillinuxng}/sbin:$PATH
newDevices=1
# If we mount any file system, we repeat this loop, because new
# mount opportunities may have become available (such as images
# for loopback mounts).
while test -n "$newDevices"; do
newDevices=
${flip concatMapStrings fileSystems (fs: ''
for dummy in x; do # make `continue' work
mountPoint='${fs.mountPoint}'
device='${if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}"}'
fsType='${fs.fsType}'
# A device is a pseudo-device (i.e. not an actual device
# node) if it's not an absolute path (e.g. an NFS server
# such as machine:/path), if it starts with // (a CIFS FS),
# a known pseudo filesystem (such as tmpfs), or the device
# is a directory (e.g. a bind mount).
isPseudo=
test "''${device:0:1}" != / -o "''${device:0:2}" = // -o "$fsType" = "tmpfs" \
-o -d "$device" && isPseudo=1
if ! test -n "$isPseudo" -o -e "$device"; then
echo "skipping $device, doesn't exist (yet)"
continue
fi
# !!! quick hack: if the mount point is already mounted, try
# a remount to change the options but nothing else.
if cat /proc/mounts | grep -F -q " $mountPoint "; then
if test "''${device:0:2}" != //; then
echo "remounting $device on $mountPoint"
${mount}/bin/mount -t "$fsType" \
-o remount,"${fs.options}" \
"$device" "$mountPoint" || true
fi
continue
fi
# If $device is already mounted somewhere else, unmount it first.
# !!! Note: we use /etc/mtab, not /proc/mounts, because mtab
# contains more accurate info when using loop devices.
if test -z "$isPseudo"; then
device=$(readlink -f "$device")
prevMountPoint=$(
cat /etc/mtab \
| grep "^$device " \
| sed 's|^[^ ]\+ \+\([^ ]\+\).*|\1|' \
)
if test "$prevMountPoint" = "$mountPoint"; then
echo "remounting $device on $mountPoint"
${mount}/bin/mount -t "$fsType" \
-o remount,"${fs.options}" \
"$device" "$mountPoint" || true
continue
fi
if test -n "$prevMountPoint"; then
echo "unmount $device from $prevMountPoint"
${mount}/bin/umount "$prevMountPoint" || true
fi
fi
echo "mounting $device on $mountPoint"
# !!! should do something with the result; also prevent repeated fscks.
if test -z "$isPseudo"; then
fsck -a "$device" || true
fi
${optionalString fs.autocreate
''
mkdir -p "$mountPoint"
''
}
if ${mount}/bin/mount -t "$fsType" -o "${fs.options}" "$device" "$mountPoint"; then
newDevices=1
fi
done
'')}
done
'';
in
{
###### interface
@ -221,12 +119,44 @@ in
config = {
# Add the mount helpers to the system path so that `mount' can find them.
environment.systemPackages = [pkgs.ntfs3g pkgs.cifs_utils pkgs.nfsUtils];
environment.systemPackages = [ pkgs.ntfs3g pkgs.cifs_utils pkgs.nfsUtils pkgs.mountall ];
jobs.filesystems =
{ startOn = [ "new-devices" "ip-up" ];
environment.etc = singleton
{ source = pkgs.writeText "fstab"
''
# This is a generated file. Do not edit!
script = task;
# Filesystems.
${flip concatMapStrings config.fileSystems (fs:
(if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}")
+ " " + fs.mountPoint
+ " " + fs.fsType
+ " " + fs.options
+ " 0"
+ " " + (if fs.mountPoint == "/" then "1" else "2")
+ "\n"
)}
# Swap devices.
${flip concatMapStrings config.swapDevices (sw:
"${sw.device} none swap\n"
)}
'';
target = "fstab";
};
jobs.mountall =
{ startOn = "started udev";
script =
''
exec > /dev/console 2>&1
export PATH=${config.system.sbin.mount}/bin:${pkgs.utillinux}/sbin:$PATH
${pkgs.mountall}/sbin/mountall --verbose --debug
echo DONE
'';
extraConfig = "console owner";
task = true;
};

View file

@ -2,12 +2,6 @@
with pkgs.lib;
let
inherit (pkgs) cryptsetup utillinux;
in
{
###### interface
@ -36,37 +30,31 @@ in
options = {config, options, ...}: {
options = {
device = mkOption {
example = "/dev/sda3";
type = types.string;
description = ''
Path of the device.
'';
description = "Path of the device.";
};
label = mkOption {
example = "swap";
type = types.string;
description = "
description = ''
Label of the device. Can be used instead of <varname>device</varname>.
";
'';
};
cipher = mkOption {
default = false;
example = true;
type = types.bool;
description = "
Cipher the swap device to protect swapped data. This option
description = ''
Encrypt the swap device to protect swapped data. This option
does not work with labels.
";
'';
};
command = mkOption {
description = "
Command used to activate the swap device.
";
};
};
config = {
@ -75,59 +63,12 @@ in
"/dev/disk/by-label/${config.label}"
else
mkNotdef;
command = ''
if test -e "${config.device}"; then
${if config.cipher then ''
plainDevice="${config.device}"
name="crypt$(echo "$plainDevice" | sed -e 's,/,.,g')"
device="/dev/mapper/$name"
if ! test -e "$device"; then
${cryptsetup}/sbin/cryptsetup -c aes -s 128 -d /dev/urandom create "$name" "$plainDevice"
${utillinux}/sbin/mkswap -f "$device" || true
fi
''
else ''
device="${config.device}"
''
}
device=$(readlink -f "$device")
# Add new swap devices.
if echo $unused | grep -q "^$device\$"; then
unused="$(echo $unused | grep -v "^$device\$" || true)"
else
${utillinux}/sbin/swapon "$device" || true
fi
fi
'';
};
};
};
};
###### implementation
config = {
jobs.swap =
{ task = true;
startOn = ["startup" "new-devices"];
script =
''
unused="$(sed '1d; s/ .*//' /proc/swaps)"
${toString (map (x: x.command) config.swapDevices)}
# Remove remaining swap devices.
test -n "$unused" && ${utillinux}/sbin/swapoff $unused || true
'';
};
};
}