about summary refs log tree commit diff
diff options
context:
space:
mode:
authoroxalica <oxalicc@pm.me>2022-10-04 11:08:59 +0800
committeroxalica <oxalicc@pm.me>2023-01-17 06:47:21 +0800
commit87a0c9490d0c97f1dd40454b47a416d7477320ff (patch)
tree858bee4104c0e81203da403b64d816f16ab2335a
parente24b481e0a29f76d53c9962a48b2ab4a88498f00 (diff)
nixos/swap: fix creation on BTRFS and refactor assertions
-rw-r--r--nixos/modules/config/swap.nix36
1 files changed, 27 insertions, 9 deletions
diff --git a/nixos/modules/config/swap.nix b/nixos/modules/config/swap.nix
index 76a054b100ebe..2c9c4c9c1a2d8 100644
--- a/nixos/modules/config/swap.nix
+++ b/nixos/modules/config/swap.nix
@@ -66,7 +66,7 @@ let
 
       device = mkOption {
         example = "/dev/sda3";
-        type = types.str;
+        type = types.nonEmptyStr;
         description = lib.mdDoc "Path of the device or swap file.";
       };
 
@@ -197,6 +197,21 @@ in
   };
 
   config = mkIf ((length config.swapDevices) != 0) {
+    assertions = map (sw: {
+      assertion = sw.randomEncryption.enable -> builtins.match "/dev/disk/by-(uuid|label)/.*" sw.device == null;
+      message = ''
+        You cannot use swap device "${sw.device}" with randomEncryption enabled.
+        The UUIDs and labels will get erased on every boot when the partition is encrypted.
+        Use /dev/disk/by-partuuid/… instead.
+      '';
+    }) config.swapDevices;
+
+    warnings =
+      concatMap (sw:
+        if sw.size != null && hasPrefix "/dev/" sw.device
+        then [ "Setting the swap size of block device ${sw.device} has no effect" ]
+        else [ ])
+      config.swapDevices;
 
     system.requiredKernelConfig = with config.lib.kernelConfig; [
       (isYes "SWAP")
@@ -205,24 +220,27 @@ in
     # Create missing swapfiles.
     systemd.services =
       let
-
         createSwapDevice = sw:
-          assert sw.device != "";
-          assert !(sw.randomEncryption.enable && lib.hasPrefix "/dev/disk/by-uuid"  sw.device);
-          assert !(sw.randomEncryption.enable && lib.hasPrefix "/dev/disk/by-label" sw.device);
           let realDevice' = escapeSystemdPath sw.realDevice;
           in nameValuePair "mkswap-${sw.deviceName}"
           { description = "Initialisation of swap device ${sw.device}";
             wantedBy = [ "${realDevice'}.swap" ];
             before = [ "${realDevice'}.swap" ];
-            path = [ pkgs.util-linux ] ++ optional sw.randomEncryption.enable pkgs.cryptsetup;
+            path = [ pkgs.util-linux pkgs.e2fsprogs ]
+              ++ optional sw.randomEncryption.enable pkgs.cryptsetup;
+
+            environment.DEVICE = sw.device;
 
             script =
               ''
                 ${optionalString (sw.size != null) ''
-                  currentSize=$(( $(stat -c "%s" "${sw.device}" 2>/dev/null || echo 0) / 1024 / 1024 ))
-                  if [ "${toString sw.size}" != "$currentSize" ]; then
-                    dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
+                  currentSize=$(( $(stat -c "%s" "$DEVICE" 2>/dev/null || echo 0) / 1024 / 1024 ))
+                  if [[ ! -b "$DEVICE" && "${toString sw.size}" != "$currentSize" ]]; then
+                    # Disable CoW for CoW based filesystems like BTRFS.
+                    truncate --size 0 "$DEVICE"
+                    chattr +C "$DEVICE" 2>/dev/null || true
+
+                    dd if=/dev/zero of="$DEVICE" bs=1M count=${toString sw.size}
                     chmod 0600 ${sw.device}
                     ${optionalString (!sw.randomEncryption.enable) "mkswap ${sw.realDevice}"}
                   fi