diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index 620d76aef20d8..1f79511da062f 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -158,6 +158,16 @@ in { ''; }; + managerEnvironment = mkOption { + type = with types; attrsOf (nullOr (oneOf [ str path package ])); + default = {}; + example = { SYSTEMD_LOG_LEVEL = "debug"; }; + description = lib.mdDoc '' + Environment variables of PID 1. These variables are + *not* passed to started units. + ''; + }; + contents = mkOption { description = lib.mdDoc "Set of files that have to be linked into the initrd"; example = literalExpression '' @@ -355,8 +365,11 @@ in { less = "${pkgs.less}/bin/less"; mount = "${cfg.package.util-linux}/bin/mount"; umount = "${cfg.package.util-linux}/bin/umount"; + fsck = "${cfg.package.util-linux}/bin/fsck"; }; + managerEnvironment.PATH = "/bin:/sbin"; + contents = { "/init".source = "${cfg.package}/lib/systemd/systemd"; "/etc/systemd/system".source = stage1Units; @@ -365,6 +378,7 @@ in { [Manager] DefaultEnvironment=PATH=/bin:/sbin ${optionalString (isBool cfg.emergencyAccess && cfg.emergencyAccess) "SYSTEMD_SULOGIN_FORCE=1"} ${cfg.extraConfig} + ManagerEnvironment=${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${lib.escapeShellArg v}") cfg.managerEnvironment)} ''; "/lib/modules".source = "${modulesClosure}/lib/modules"; @@ -447,21 +461,6 @@ in { (v: let n = escapeSystemdPath v.where; in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); - # The unit in /run/systemd/generator shadows the unit in - # /etc/systemd/system, but will still apply drop-ins from - # /etc/systemd/system/foo.service.d/ - # - # We need IgnoreOnIsolate, otherwise the Requires dependency of - # a mount unit on its makefs unit causes it to be unmounted when - # we isolate for switch-root. Use a dummy package so that - # generateUnits will generate drop-ins instead of unit files. - packages = [(pkgs.runCommand "dummy" {} '' - mkdir -p $out/etc/systemd/system - touch $out/etc/systemd/system/systemd-{makefs,growfs}@.service - '')]; - services."systemd-makefs@" = lib.mkIf needMakefs { unitConfig.IgnoreOnIsolate = true; }; - services."systemd-growfs@" = lib.mkIf needGrowfs { unitConfig.IgnoreOnIsolate = true; }; - # make sure all the /dev nodes are set up services.systemd-tmpfiles-setup-dev.wantedBy = ["sysinit.target"]; diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index 7f2c8a41b20a1..822f1593474eb 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -140,7 +140,10 @@ let else if config.fsType == "reiserfs" then "-q" else null; in { - options = mkIf config.autoResize [ "x-nixos.autoresize" ]; + options = mkMerge [ + (mkIf config.autoResize [ "x-nixos.autoresize" ]) + (mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ]) + ]; formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions); }; @@ -155,27 +158,54 @@ let makeFstabEntries = let - fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "nfs4" "vboxsf" "glusterfs" "apfs" "9p" "cifs" "prl_fs" "vmhgfs" ]; + fsToSkipCheck = [ + "none" + "auto" + "overlay" + "iso9660" + "bindfs" + "udf" + "btrfs" + "zfs" + "tmpfs" + "bcachefs" + "nfs" + "nfs4" + "nilfs2" + "vboxsf" + "squashfs" + "glusterfs" + "apfs" + "9p" + "cifs" + "prl_fs" + "vmhgfs" + ] ++ lib.optionals (!config.boot.initrd.checkJournalingFS) [ + "ext3" + "ext4" + "reiserfs" + "xfs" + "jfs" + "f2fs" + ]; isBindMount = fs: builtins.elem "bind" fs.options; skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck || isBindMount fs; # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; - in fstabFileSystems: { rootPrefix ? "", excludeChecks ? false, extraOpts ? (fs: []) }: concatMapStrings (fs: + in fstabFileSystems: { rootPrefix ? "", extraOpts ? (fs: []) }: concatMapStrings (fs: (optionalString (isBindMount fs) (escape rootPrefix)) + (if fs.device != null then escape fs.device else if fs.label != null then "/dev/disk/by-label/${escape fs.label}" else throw "No device specified for mount point ‘${fs.mountPoint}’.") - + " " + escape (rootPrefix + fs.mountPoint) + + " " + escape fs.mountPoint + " " + fs.fsType + " " + escape (builtins.concatStringsSep "," (fs.options ++ (extraOpts fs))) - + " " + (optionalString (!excludeChecks) - ("0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2"))) + + " 0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2") + "\n" ) fstabFileSystems; initrdFstab = pkgs.writeText "initrd-fstab" (makeFstabEntries (filter utils.fsNeededForBoot fileSystems) { rootPrefix = "/sysroot"; - excludeChecks = true; extraOpts = fs: (optional fs.autoResize "x-systemd.growfs") ++ (optional fs.autoFormat "x-systemd.makefs"); @@ -328,7 +358,9 @@ in )} ''; - boot.initrd.systemd.contents."/etc/fstab".source = initrdFstab; + boot.initrd.systemd.storePaths = [initrdFstab]; + boot.initrd.systemd.managerEnvironment.SYSTEMD_SYSROOT_FSTAB = initrdFstab; + boot.initrd.systemd.services.initrd-parse-etc.environment.SYSTEMD_SYSROOT_FSTAB = initrdFstab; # Provide a target that pulls in all filesystems. systemd.targets.fs = diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 06210529eb8c4..700fccb5ebd40 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -1084,15 +1084,17 @@ in what = "overlay"; type = "overlay"; options = "lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/store,workdir=/sysroot/nix/.rw-store/work"; - wantedBy = ["local-fs.target"]; - before = ["local-fs.target"]; - requires = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; - after = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; - unitConfig.IgnoreOnIsolate = true; + wantedBy = ["initrd-fs.target"]; + before = ["initrd-fs.target"]; + requires = ["rw-store.service"]; + after = ["rw-store.service"]; + unitConfig.RequiresMountsFor = "/sysroot/nix/.ro-store"; }]; services.rw-store = { - after = ["sysroot-nix-.rw\\x2dstore.mount"]; - unitConfig.DefaultDependencies = false; + unitConfig = { + DefaultDependencies = false; + RequiresMountsFor = "/sysroot/nix/.rw-store"; + }; serviceConfig = { Type = "oneshot"; ExecStart = "/bin/mkdir -p 0755 /sysroot/nix/.rw-store/store /sysroot/nix/.rw-store/work /sysroot/nix/store"; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 7ee83be6672e4..503e084089a1e 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -233,6 +233,7 @@ in { freshrss-pgsql = handleTest ./freshrss-pgsql.nix {}; frr = handleTest ./frr.nix {}; fsck = handleTest ./fsck.nix {}; + fsck-systemd-stage-1 = handleTest ./fsck.nix { systemdStage1 = true; }; ft2-clone = handleTest ./ft2-clone.nix {}; mimir = handleTest ./mimir.nix {}; garage = handleTest ./garage {}; diff --git a/nixos/tests/fsck.nix b/nixos/tests/fsck.nix index 5b8b09f433a22..ccb664be080c6 100644 --- a/nixos/tests/fsck.nix +++ b/nixos/tests/fsck.nix @@ -1,3 +1,9 @@ +{ system ? builtins.currentSystem +, config ? {} +, pkgs ? import ../.. { inherit system config; } +, systemdStage1 ? false +}: + import ./make-test-python.nix { name = "fsck"; @@ -11,13 +17,17 @@ import ./make-test-python.nix { autoFormat = true; }; }; + + boot.initrd.systemd.enable = systemdStage1; }; testScript = '' machine.wait_for_unit("default.target") with subtest("root fs is fsckd"): - machine.succeed("journalctl -b | grep 'fsck.ext4.*/dev/vda'") + machine.succeed("journalctl -b | grep '${if systemdStage1 + then "fsck.*vda.*clean" + else "fsck.ext4.*/dev/vda"}'") with subtest("mnt fs is fsckd"): machine.succeed("journalctl -b | grep 'fsck.*/dev/vdb.*clean'") diff --git a/pkgs/os-specific/linux/systemd/0004-Look-for-fsck-in-the-right-place.patch b/pkgs/os-specific/linux/systemd/0004-Look-for-fsck-in-the-right-place.patch index 431e79a55d50f..1e602fdee6b91 100644 --- a/pkgs/os-specific/linux/systemd/0004-Look-for-fsck-in-the-right-place.patch +++ b/pkgs/os-specific/linux/systemd/0004-Look-for-fsck-in-the-right-place.patch @@ -4,19 +4,30 @@ Date: Thu, 1 May 2014 14:10:10 +0200 Subject: [PATCH] Look for fsck in the right place --- - src/fsck/fsck.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + src/fsck/fsck.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c -index 595434ab57..374a4e6c76 100644 +index 73c76fceea..d00cea7158 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c -@@ -373,7 +373,7 @@ static int run(int argc, char *argv[]) { +@@ -352,6 +352,7 @@ static int run(int argc, char *argv[]) { + if (r == 0) { + char dash_c[STRLEN("-C") + DECIMAL_STR_MAX(int) + 1]; + int progress_socket = -1; ++ _cleanup_free_ char *fsck_name = NULL; + const char *cmdline[9]; + int i = 0; + +@@ -372,7 +373,10 @@ static int run(int argc, char *argv[]) { } else dash_c[0] = 0; - cmdline[i++] = "/sbin/fsck"; -+ cmdline[i++] = "/run/current-system/sw/bin/fsck"; ++ r = find_executable("fsck", &fsck_name); ++ if (r < 0) ++ return r; ++ cmdline[i++] = fsck_name; cmdline[i++] = arg_repair; cmdline[i++] = "-T";