diff options
Diffstat (limited to 'nixpkgs/nixos/modules/tasks/filesystems.nix')
-rw-r--r-- | nixpkgs/nixos/modules/tasks/filesystems.nix | 200 |
1 files changed, 113 insertions, 87 deletions
diff --git a/nixpkgs/nixos/modules/tasks/filesystems.nix b/nixpkgs/nixos/modules/tasks/filesystems.nix index 318740a44f4a..7cb2ca23fa41 100644 --- a/nixpkgs/nixos/modules/tasks/filesystems.nix +++ b/nixpkgs/nixos/modules/tasks/filesystems.nix @@ -33,7 +33,16 @@ let mountPoint = mkOption { example = "/mnt/usb"; type = nonEmptyWithoutTrailingSlash; - description = lib.mdDoc "Location of the mounted the file system."; + description = lib.mdDoc "Location of the mounted file system."; + }; + + stratis.poolUuid = lib.mkOption { + type = types.uniq (types.nullOr types.str); + description = lib.mdDoc '' + UUID of the stratis pool that the fs is located in + ''; + example = "04c68063-90a5-4235-b9dd-6180098a20d9"; + default = null; }; device = mkOption { @@ -54,7 +63,7 @@ let default = [ "defaults" ]; example = [ "data=journal" ]; description = lib.mdDoc "Options used to mount the file system."; - type = types.listOf nonEmptyStr; + type = types.nonEmptyListOf nonEmptyStr; }; depends = mkOption { @@ -103,12 +112,9 @@ let }; formatOptions = mkOption { - default = ""; - type = types.str; - description = lib.mdDoc '' - If {option}`autoFormat` option is set specifies - extra options passed to mkfs. - ''; + visible = false; + type = types.unspecified; + default = null; }; autoResize = mkOption { @@ -130,19 +136,11 @@ let }; - config = let - defaultFormatOptions = - # -F needed to allow bare block device without partitions - if (builtins.substring 0 3 config.fsType) == "ext" then "-F" - # -q needed for non-interactive operations - else if config.fsType == "jfs" then "-q" - # (same here) - else if config.fsType == "reiserfs" then "-q" - else null; - in { - options = mkIf config.autoResize [ "x-nixos.autoresize" ]; - formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions); - }; + config.options = mkMerge [ + (mkIf config.autoResize [ "x-systemd.growfs" ]) + (mkIf config.autoFormat [ "x-systemd.makefs" ]) + (mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ]) + ]; }; @@ -153,6 +151,58 @@ let specialMount "${mount.device}" "${mount.mountPoint}" "${concatStringsSep "," mount.options}" "${mount.fsType}" '') mounts); + makeFstabEntries = + let + 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 ? "" }: 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 fs.mountPoint + + " " + fs.fsType + + " " + escape (builtins.concatStringsSep "," fs.options) + + " 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"; + }); + in { @@ -175,28 +225,27 @@ in } ''; type = types.attrsOf (types.submodule [coreFileSystemOpts fileSystemOpts]); - description = '' + description = lib.mdDoc '' The file systems to be mounted. It must include an entry for - the root directory (<literal>mountPoint = "/"</literal>). Each + the root directory (`mountPoint = "/"`). Each entry in the list is an attribute set with the following fields: - <literal>mountPoint</literal>, <literal>device</literal>, - <literal>fsType</literal> (a file system type recognised by - <command>mount</command>; defaults to - <literal>"auto"</literal>), and <literal>options</literal> - (the mount options passed to <command>mount</command> using the - <option>-o</option> flag; defaults to <literal>[ "defaults" ]</literal>). - - Instead of specifying <literal>device</literal>, you can also - specify a volume label (<literal>label</literal>) for file - systems that support it, such as ext2/ext3 (see <command>mke2fs - -L</command>). + `mountPoint`, `device`, + `fsType` (a file system type recognised by + {command}`mount`; defaults to + `"auto"`), and `options` + (the mount options passed to {command}`mount` using the + {option}`-o` flag; defaults to `[ "defaults" ]`). + + Instead of specifying `device`, you can also + specify a volume label (`label`) for file + systems that support it, such as ext2/ext3 (see {command}`mke2fs -L`). ''; }; system.fsPackages = mkOption { internal = true; default = [ ]; - description = "Packages supplying file system mounters and checkers."; + description = lib.mdDoc "Packages supplying file system mounters and checkers."; }; boot.supportedFilesystems = mkOption { @@ -210,7 +259,7 @@ in default = {}; type = types.attrsOf (types.submodule coreFileSystemOpts); internal = true; - description = '' + description = lib.mdDoc '' Special filesystems that are mounted very early during boot. ''; }; @@ -253,7 +302,13 @@ in assertions = let ls = sep: concatMapStringsSep sep (x: x.mountPoint); - notAutoResizable = fs: fs.autoResize && !(hasPrefix "ext" fs.fsType || fs.fsType == "f2fs"); + resizableFSes = [ + "ext3" + "ext4" + "btrfs" + "xfs" + ]; + notAutoResizable = fs: fs.autoResize && !(builtins.elem fs.fsType resizableFSes); in [ { assertion = ! (fileSystems' ? cycle); message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}"; @@ -261,8 +316,21 @@ in { assertion = ! (any notAutoResizable fileSystems); message = let fs = head (filter notAutoResizable fileSystems); - in - "Mountpoint '${fs.mountPoint}': 'autoResize = true' is not supported for 'fsType = \"${fs.fsType}\"':${if fs.fsType == "auto" then " fsType has to be explicitly set and" else ""} only the ext filesystems and f2fs support it."; + in '' + Mountpoint '${fs.mountPoint}': 'autoResize = true' is not supported for 'fsType = "${fs.fsType}"' + ${optionalString (fs.fsType == "auto") "fsType has to be explicitly set and"} + only the following support it: ${lib.concatStringsSep ", " resizableFSes}. + ''; + } + { + assertion = ! (any (fs: fs.formatOptions != null) fileSystems); + message = let + fs = head (filter (fs: fs.formatOptions != null) fileSystems); + in '' + 'fileSystems.<name>.formatOptions' has been removed, since + systemd-makefs does not support any way to provide formatting + options. + ''; } ]; @@ -279,11 +347,6 @@ in environment.etc.fstab.text = let - fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "vboxsf" "glusterfs" "apfs" "9p" "cifs" "prl_fs" "vmhgfs" ]; - 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; swapOptions = sw: concatStringsSep "," ( sw.options ++ optional (sw.priority != null) "pri=${toString sw.priority}" @@ -298,18 +361,7 @@ in # <file system> <mount point> <type> <options> <dump> <pass> # Filesystems. - ${concatMapStrings (fs: - (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 fs.mountPoint - + " " + fs.fsType - + " " + builtins.concatStringsSep "," fs.options - + " 0" - + " " + (if skipCheck fs then "0" else - if fs.mountPoint == "/" then "1" else "2") - + "\n" - ) fileSystems} + ${makeFstabEntries fileSystems {}} # Swap devices. ${flip concatMapStrings config.swapDevices (sw: @@ -317,43 +369,17 @@ in )} ''; + 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 = { description = "All File Systems"; wants = [ "local-fs.target" "remote-fs.target" ]; }; - systemd.services = - - # Emit systemd services to format requested filesystems. - let - formatDevice = fs: - let - mountPoint' = "${escapeSystemdPath fs.mountPoint}.mount"; - device' = escapeSystemdPath fs.device; - device'' = "${device'}.device"; - in nameValuePair "mkfs-${device'}" - { description = "Initialisation of Filesystem ${fs.device}"; - wantedBy = [ mountPoint' ]; - before = [ mountPoint' "systemd-fsck@${device'}.service" ]; - requires = [ device'' ]; - after = [ device'' ]; - path = [ pkgs.util-linux ] ++ config.system.fsPackages; - script = - '' - if ! [ -e "${fs.device}" ]; then exit 1; fi - # FIXME: this is scary. The test could be more robust. - type=$(blkid -p -s TYPE -o value "${fs.device}" || true) - if [ -z "$type" ]; then - echo "creating ${fs.fsType} filesystem on ${fs.device}..." - mkfs.${fs.fsType} ${fs.formatOptions} "${fs.device}" - fi - ''; - unitConfig.RequiresMountsFor = [ "${dirOf fs.device}" ]; - unitConfig.DefaultDependencies = false; # needed to prevent a cycle - serviceConfig.Type = "oneshot"; - }; - in listToAttrs (map formatDevice (filter (fs: fs.autoFormat && !(utils.fsNeededForBoot fs)) fileSystems)) // { + systemd.services = { # Mount /sys/fs/pstore for evacuating panic logs and crashdumps from persistent storage onto the disk using systemd-pstore. # This cannot be done with the other special filesystems because the pstore module (which creates the mount point) is not loaded then. "mount-pstore" = { |