summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjakobrs <jakobrs100@gmail.com>2020-05-21 09:10:47 +0200
committerjakobrs <jakobrs100@gmail.com>2021-06-08 18:51:31 +0200
commitb07602a604d6d5db3b1ff85d1c3c008ad25245fa (patch)
treec0a9b740b761540b69a0639857f06c38793a5142
parentc8e32eddf825bdec9d510185357cb887622531f9 (diff)
nixos/lib, nixos/filesystems: Make fsBefore more stable, and add `depends` option
-rw-r--r--nixos/lib/utils.nix26
-rw-r--r--nixos/modules/tasks/filesystems.nix20
2 files changed, 42 insertions, 4 deletions
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix
index c9dfdbed99a3..1a51b149e56e 100644
--- a/nixos/lib/utils.nix
+++ b/nixos/lib/utils.nix
@@ -14,8 +14,30 @@ rec {
fsNeededForBoot = fs: fs.neededForBoot || elem fs.mountPoint pathsNeededForBoot;
# Check whenever `b` depends on `a` as a fileSystem
- fsBefore = a: b: a.mountPoint == b.device
- || hasPrefix "${a.mountPoint}${optionalString (!(hasSuffix "/" a.mountPoint)) "/"}" b.mountPoint;
+ fsBefore = a: b:
+ let
+ # normalisePath adds a slash at the end of the path if it didn't already
+ # have one.
+ #
+ # The reason slashes are added at the end of each path is to prevent `b`
+ # from accidentally depending on `a` in cases like
+ # a = { mountPoint = "/aaa"; ... }
+ # b = { device = "/aaaa"; ... }
+ # Here a.mountPoint *is* a prefix of b.device even though a.mountPoint is
+ # *not* a parent of b.device. If we add a slash at the end of each string,
+ # though, this is not a problem: "/aaa/" is not a prefix of "/aaaa/".
+ normalisePath = path: "${path}${optionalString (!(hasSuffix "/" path)) "/"}";
+ normalise = mount: mount // { device = normalisePath mount.device;
+ mountPoint = normalisePath mount.mountPoint;
+ depends = map normalisePath mount.depends;
+ };
+
+ a' = normalise a;
+ b' = normalise b;
+
+ in hasPrefix a'.mountPoint b'.device
+ || hasPrefix a'.mountPoint b'.mountPoint
+ || any (hasPrefix a'.mountPoint) b'.depends;
# Escape a path according to the systemd rules, e.g. /dev/xyzzy
# becomes dev-xyzzy. FIXME: slow.
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index 065d6cc95d18..2949c82df8fe 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -24,13 +24,15 @@ let
specialFSTypes = [ "proc" "sysfs" "tmpfs" "ramfs" "devtmpfs" "devpts" ];
+ nonEmptyWithoutTrailingSlash = addCheckDesc "non-empty without trailing slash" types.str
+ (s: isNonEmpty s && (builtins.match ".+/" s) == null);
+
coreFileSystemOpts = { name, config, ... }: {
options = {
mountPoint = mkOption {
example = "/mnt/usb";
- type = addCheckDesc "non-empty without trailing slash" types.str
- (s: isNonEmpty s && (builtins.match ".+/" s) == null);
+ type = nonEmptyWithoutTrailingSlash;
description = "Location of the mounted the file system.";
};
@@ -55,6 +57,20 @@ let
type = types.listOf nonEmptyStr;
};
+ depends = mkOption {
+ default = [ ];
+ example = [ "/persist" ];
+ type = types.listOf nonEmptyWithoutTrailingSlash;
+ description = ''
+ List of paths that should be mounted before this one. This filesystem's
+ <option>device</option> and <option>mountPoint</option> are always
+ checked and do not need to be included explicitly. If a path is added
+ to this list, any other filesystem whose mount point is a parent of
+ the path will be mounted before this filesystem. The paths do not need
+ to actually be the <option>mountPoint</option> of some other filesystem.
+ '';
+ };
+
};
config = {