nixos filesystems: unify early filesystems handling
A new internal config option `fileSystems.<name>.early` is added to indicate that the filesystem needs to be loaded very early (i.e. in initrd). They are transformed to a shell script in `system.build.earlyMountScript` with calls to an undefined `specialMount` function, which is expected to be caller-specific. This option is used by stage-1, stage-2 and activation script to set up and remount those filesystems. Options for them are updated according to systemd defaults.
This commit is contained in:
parent
3f70fcd4c1
commit
6efcfe03ae
|
@ -20,23 +20,6 @@ with lib;
|
||||||
config = mkIf config.security.hideProcessInformation {
|
config = mkIf config.security.hideProcessInformation {
|
||||||
users.groups.proc.gid = config.ids.gids.proc;
|
users.groups.proc.gid = config.ids.gids.proc;
|
||||||
|
|
||||||
systemd.services.hidepid = {
|
fileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ];
|
||||||
wantedBy = [ "local-fs.target" ];
|
|
||||||
after = [ "systemd-remount-fs.service" ];
|
|
||||||
before = [ "local-fs-pre.target" "local-fs.target" "shutdown.target" ];
|
|
||||||
wants = [ "local-fs-pre.target" ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=2,gid=${toString config.ids.gids.proc} /proc'';
|
|
||||||
ExecStop = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=0,gid=0 /proc'';
|
|
||||||
};
|
|
||||||
|
|
||||||
unitConfig = {
|
|
||||||
DefaultDependencies = false;
|
|
||||||
Conflicts = "shutdown.target";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,9 +154,15 @@ in
|
||||||
|
|
||||||
system.activationScripts.tmpfs =
|
system.activationScripts.tmpfs =
|
||||||
''
|
''
|
||||||
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
|
specialMount() {
|
||||||
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
|
local device="$1"
|
||||||
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
|
local mountPoint="$2"
|
||||||
|
local options="$3"
|
||||||
|
local fsType="$4"
|
||||||
|
|
||||||
|
${pkgs.utillinux}/bin/mount -t "$fsType" -o "remount,$options" "$device" "$mountPoint"
|
||||||
|
}
|
||||||
|
source ${config.system.build.earlyMountScript}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,22 +59,24 @@ echo
|
||||||
echo "[1;32m<<< NixOS Stage 1 >>>[0m"
|
echo "[1;32m<<< NixOS Stage 1 >>>[0m"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
# Make several required directories.
|
||||||
# Mount special file systems.
|
|
||||||
mkdir -p /etc/udev
|
mkdir -p /etc/udev
|
||||||
touch /etc/fstab # to shut up mount
|
touch /etc/fstab # to shut up mount
|
||||||
touch /etc/mtab # to shut up mke2fs
|
ln -s /proc/mounts /etc/mtab # to shut up mke2fs
|
||||||
touch /etc/udev/hwdb.bin # to shut up udev
|
touch /etc/udev/hwdb.bin # to shut up udev
|
||||||
touch /etc/initrd-release
|
touch /etc/initrd-release
|
||||||
mkdir -p /proc
|
|
||||||
mount -t proc proc /proc
|
# Mount special file systems.
|
||||||
mkdir -p /sys
|
specialMount() {
|
||||||
mount -t sysfs sysfs /sys
|
local device="$1"
|
||||||
mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev
|
local mountPoint="$2"
|
||||||
mkdir -p /run
|
local options="$3"
|
||||||
mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
|
local fsType="$4"
|
||||||
mkdir /dev/pts
|
|
||||||
mount -t devpts devpts /dev/pts
|
mkdir -m 0755 -p "$mountPoint"
|
||||||
|
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
|
||||||
|
}
|
||||||
|
source @earlyMountScript@
|
||||||
|
|
||||||
# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
|
# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
|
||||||
mkdir -p /tmp
|
mkdir -p /tmp
|
||||||
|
|
|
@ -190,7 +190,9 @@ let
|
||||||
|
|
||||||
inherit udevRules extraUtils modulesClosure;
|
inherit udevRules extraUtils modulesClosure;
|
||||||
|
|
||||||
inherit (config.boot) resumeDevice devSize runSize;
|
inherit (config.boot) resumeDevice;
|
||||||
|
|
||||||
|
inherit (config.system.build) earlyMountScript;
|
||||||
|
|
||||||
inherit (config.boot.initrd) checkJournalingFS
|
inherit (config.boot.initrd) checkJournalingFS
|
||||||
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;
|
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;
|
||||||
|
|
|
@ -37,12 +37,16 @@ fi
|
||||||
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
|
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
|
||||||
# stage 1, we need to do that here.
|
# stage 1, we need to do that here.
|
||||||
if [ ! -e /proc/1 ]; then
|
if [ ! -e /proc/1 ]; then
|
||||||
mkdir -m 0755 -p /proc
|
specialMount() {
|
||||||
mount -n -t proc proc /proc
|
local device="$1"
|
||||||
mkdir -m 0755 -p /dev
|
local mountPoint="$2"
|
||||||
mount -t devtmpfs devtmpfs /dev
|
local options="$3"
|
||||||
mkdir -m 0755 -p /sys
|
local fsType="$4"
|
||||||
mount -t sysfs sysfs /sys
|
|
||||||
|
mkdir -m 0755 -p "$mountPoint"
|
||||||
|
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
|
||||||
|
}
|
||||||
|
source @earlyMountScript@
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,11 +91,6 @@ done
|
||||||
|
|
||||||
|
|
||||||
# More special file systems, initialise required directories.
|
# More special file systems, initialise required directories.
|
||||||
if ! mountpoint -q /dev/shm; then
|
|
||||||
mkdir -m 0755 /dev/shm
|
|
||||||
mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
|
|
||||||
fi
|
|
||||||
mkdir -m 0755 -p /dev/pts
|
|
||||||
[ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
|
[ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
|
||||||
mkdir -m 01777 -p /tmp
|
mkdir -m 01777 -p /tmp
|
||||||
mkdir -m 0755 -p /var /var/log /var/lib /var/db
|
mkdir -m 0755 -p /var /var/log /var/lib /var/db
|
||||||
|
@ -112,14 +111,6 @@ rm -f /etc/{group,passwd,shadow}.lock
|
||||||
rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
|
rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
|
||||||
|
|
||||||
|
|
||||||
# Create a tmpfs on /run to hold runtime state for programs such as
|
|
||||||
# udev (if stage 1 hasn't already done so).
|
|
||||||
if ! mountpoint -q /run; then
|
|
||||||
rm -rf /run
|
|
||||||
mkdir -m 0755 -p /run
|
|
||||||
mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a ramfs on /run/keys to hold secrets that shouldn't be
|
# Create a ramfs on /run/keys to hold secrets that shouldn't be
|
||||||
# written to disk (generally used for NixOps, harmless elsewhere).
|
# written to disk (generally used for NixOps, harmless elsewhere).
|
||||||
if ! mountpoint -q /run/keys; then
|
if ! mountpoint -q /run/keys; then
|
||||||
|
|
|
@ -20,10 +20,9 @@ let
|
||||||
src = ./stage-2-init.sh;
|
src = ./stage-2-init.sh;
|
||||||
shellDebug = "${pkgs.bashInteractive}/bin/bash";
|
shellDebug = "${pkgs.bashInteractive}/bin/bash";
|
||||||
isExecutable = true;
|
isExecutable = true;
|
||||||
inherit (config.boot) devShmSize runSize;
|
|
||||||
inherit (config.nix) readOnlyStore;
|
inherit (config.nix) readOnlyStore;
|
||||||
inherit (config.networking) useHostResolvConf;
|
inherit (config.networking) useHostResolvConf;
|
||||||
ttyGid = config.ids.gids.tty;
|
inherit (config.system.build) earlyMountScript;
|
||||||
path =
|
path =
|
||||||
[ pkgs.coreutils
|
[ pkgs.coreutils
|
||||||
pkgs.utillinux
|
pkgs.utillinux
|
||||||
|
|
|
@ -18,6 +18,8 @@ let
|
||||||
|
|
||||||
prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
|
prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
|
||||||
|
|
||||||
|
specialFSTypes = [ "proc" "sysfs" "tmpfs" "devtmpfs" "devpts" ];
|
||||||
|
|
||||||
fileSystemOpts = { name, config, ... }: {
|
fileSystemOpts = { name, config, ... }: {
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
@ -97,11 +99,22 @@ let
|
||||||
description = "Disable running fsck on this filesystem.";
|
description = "Disable running fsck on this filesystem.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
early = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
internal = true;
|
||||||
|
description = ''
|
||||||
|
Mount this filesystem very early during boot. At the moment of
|
||||||
|
mounting no disks are exposed, so this option is primarily for
|
||||||
|
special file systems.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
mountPoint = mkDefault name;
|
mountPoint = mkDefault name;
|
||||||
device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
|
device = mkIf (elem config.fsType specialFSTypes) (mkDefault config.fsType);
|
||||||
options = mkIf config.autoResize [ "x-nixos.autoresize" ];
|
options = mkIf config.autoResize [ "x-nixos.autoresize" ];
|
||||||
|
|
||||||
# -F needed to allow bare block device without partitions
|
# -F needed to allow bare block device without partitions
|
||||||
|
@ -110,6 +123,13 @@ let
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Makes sequence of `specialMount device mountPoint options fsType` commands.
|
||||||
|
# `systemMount` should be defined in the sourcing script.
|
||||||
|
makeSpecialMounts = mounts:
|
||||||
|
pkgs.writeText "mounts.sh" (concatMapStringsSep "\n" (mount: ''
|
||||||
|
specialMount "${mount.device}" "${mount.mountPoint}" "${concatStringsSep "," mount.options}" "${mount.fsType}"
|
||||||
|
'') mounts);
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -131,8 +151,7 @@ in
|
||||||
"/bigdisk".label = "bigdisk";
|
"/bigdisk".label = "bigdisk";
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
type = types.loaOf types.optionSet;
|
type = types.loaOf (types.submodule fileSystemOpts);
|
||||||
options = [ fileSystemOpts ];
|
|
||||||
description = ''
|
description = ''
|
||||||
The file systems to be mounted. It must include an entry for
|
The file systems to be mounted. It must include an entry for
|
||||||
the root directory (<literal>mountPoint = "/"</literal>). Each
|
the root directory (<literal>mountPoint = "/"</literal>). Each
|
||||||
|
@ -177,10 +196,14 @@ in
|
||||||
{ assertion = ! (fileSystems' ? "cycle");
|
{ assertion = ! (fileSystems' ? "cycle");
|
||||||
message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
|
message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
|
||||||
}
|
}
|
||||||
|
{ assertion = all (x: !x.early || (x.label == null && !x.autoFormat && !x.autoResize)) fileSystems;
|
||||||
|
message = "Early filesystems don't support mounting by label, auto formatting and resizing";
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
# Export for use in other modules
|
# Export for use in other modules
|
||||||
system.build.fileSystems = fileSystems;
|
system.build.fileSystems = fileSystems;
|
||||||
|
system.build.earlyMountScript = makeSpecialMounts (filter (fs: fs.early) fileSystems);
|
||||||
|
|
||||||
boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
|
boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
|
||||||
|
|
||||||
|
@ -211,7 +234,7 @@ in
|
||||||
+ " " + (if skipCheck fs then "0" else
|
+ " " + (if skipCheck fs then "0" else
|
||||||
if fs.mountPoint == "/" then "1" else "2")
|
if fs.mountPoint == "/" then "1" else "2")
|
||||||
+ "\n"
|
+ "\n"
|
||||||
) fileSystems}
|
) (filter (fs: !fs.early) fileSystems)}
|
||||||
|
|
||||||
# Swap devices.
|
# Swap devices.
|
||||||
${flip concatMapStrings config.swapDevices (sw:
|
${flip concatMapStrings config.swapDevices (sw:
|
||||||
|
@ -258,6 +281,16 @@ in
|
||||||
|
|
||||||
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
|
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
|
||||||
|
|
||||||
|
# Sync mount options with systemd's src/core/mount-setup.c: mount_table.
|
||||||
|
fileSystems = mapAttrs (n: fs: fs // { early = true; }) {
|
||||||
|
"/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
|
||||||
|
"/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };
|
||||||
|
"/run" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=755" "size=${config.boot.runSize}" ]; };
|
||||||
|
"/dev" = { fsType = "devtmpfs"; options = [ "nosuid" "strictatime" "mode=755" "size=${config.boot.devSize}" ]; };
|
||||||
|
"/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
|
||||||
|
"/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "gid=${toString config.ids.gids.tty}" ]; };
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue