diff --git a/example/btrfs-subvolumes.nix b/example/btrfs-subvolumes.nix index 91578ab..96979f4 100644 --- a/example/btrfs-subvolumes.nix +++ b/example/btrfs-subvolumes.nix @@ -45,6 +45,25 @@ }; # This subvolume will be created but not mounted "/test" = { }; + # Subvolume for the swapfile + "/swap" = { + mountpoint = "/.swapvol"; + swap = { + swapfile.size = "20M"; + swapfile2.size = "20M"; + swapfile2.path = "rel-path"; + }; + }; + }; + + mountpoint = "/partition-root"; + swap = { + swapfile = { + size = "20M"; + }; + swapfile1 = { + size = "20M"; + }; }; }; }; diff --git a/example/luks-btrfs-subvolumes.nix b/example/luks-btrfs-subvolumes.nix index 214d55a..509f5e9 100644 --- a/example/luks-btrfs-subvolumes.nix +++ b/example/luks-btrfs-subvolumes.nix @@ -48,6 +48,10 @@ mountpoint = "/nix"; mountOptions = [ "compress=zstd" "noatime" ]; }; + "/swap" = { + mountpoint = "/.swapvol"; + swap.swapfile.size = "20M"; + }; }; }; }; diff --git a/lib/default.nix b/lib/default.nix index a9456d1..b2e2014 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -192,7 +192,7 @@ let || lib.hasSuffix "Hook" n || isAttrsOfSubmodule o # TODO don't hardcode diskoLib.subType options. - || n == "content" || n == "partitions" || n == "datasets" + || n == "content" || n == "partitions" || n == "datasets" || n == "swap" ); in lib.toShellVars diff --git a/lib/types/btrfs.nix b/lib/types/btrfs.nix index 706054b..a4e59ef 100644 --- a/lib/types/btrfs.nix +++ b/lib/types/btrfs.nix @@ -1,4 +1,40 @@ { config, options, diskoLib, lib, rootMountPoint, parent, device, ... }: +let + swapType = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + options = { + size = lib.mkOption { + type = lib.types.strMatching "^([0-9]+[KMGTP])?$"; + description = "Size of the swap file (e.g. 2G)"; + }; + + path = lib.mkOption { + type = lib.types.str; + default = name; + description = "Path to the swap file (relative to the mountpoint)"; + }; + }; + })); + default = { }; + description = "Swap files"; + }; + + swapConfig = { mountpoint, swap }: + { + swapDevices = builtins.map + (file: { + device = "${mountpoint}/${file.path}"; + }) + (lib.attrValues swap); + }; + + swapCreate = mountpoint: swap: + lib.concatMapStringsSep + "\n" + (file: ''btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}"'') + (lib.attrValues swap); + +in { options = { type = lib.mkOption { @@ -50,6 +86,7 @@ default = null; description = "Location to mount the subvolume to."; }; + swap = swapType; }; })); default = { }; @@ -60,6 +97,7 @@ default = null; description = "A path to mount the BTRFS filesystem to."; }; + swap = swapType; _parent = lib.mkOption { internal = true; default = parent; @@ -75,12 +113,21 @@ inherit config options; default = '' mkfs.btrfs ${config.device} ${toString config.extraArgs} + ${lib.optionalString (config.swap != {}) '' + ( + MNTPOINT=$(mktemp -d) + mount ${device} "$MNTPOINT" -o subvol=/ + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + ${swapCreate "$MNTPOINT" config.swap} + ) + ''} ${lib.concatMapStrings (subvol: '' ( MNTPOINT=$(mktemp -d) mount ${config.device} "$MNTPOINT" -o subvol=/ trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT btrfs subvolume create "$MNTPOINT"/${subvol.name} ${toString subvol.extraArgs} + ${swapCreate "$MNTPOINT/${subvol.name}" subvol.swap} ) '') (lib.attrValues config.subvolumes)} ''; @@ -141,6 +188,14 @@ options = config.mountOptions; }; }) + (map + (subvol: swapConfig { + inherit (subvol) mountpoint swap; + }) + (lib.attrValues config.subvolumes)) + (swapConfig { + inherit (config) mountpoint swap; + }) ]; description = "NixOS configuration"; }; diff --git a/tests/btrfs-subvolumes.nix b/tests/btrfs-subvolumes.nix index 4808773..7059c1a 100644 --- a/tests/btrfs-subvolumes.nix +++ b/tests/btrfs-subvolumes.nix @@ -11,6 +11,10 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("btrfs subvolume list / | grep -qs 'path test$'"); machine.succeed("btrfs subvolume list / | grep -qs 'path nix$'"); machine.succeed("btrfs subvolume list / | grep -qs 'path home$'"); + machine.succeed("test -e /.swapvol/swapfile"); + machine.succeed("test -e /.swapvol/rel-path"); + machine.succeed("test -e /partition-root/swapfile"); + machine.succeed("test -e /partition-root/swapfile1"); ''; } diff --git a/tests/luks-btrfs-subvolumes.nix b/tests/luks-btrfs-subvolumes.nix index b10b23f..6a4e64b 100644 --- a/tests/luks-btrfs-subvolumes.nix +++ b/tests/luks-btrfs-subvolumes.nix @@ -9,5 +9,6 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("cryptsetup isLuks /dev/vda2"); machine.succeed("btrfs subvolume list / | grep -qs 'path nix$'"); machine.succeed("btrfs subvolume list / | grep -qs 'path home$'"); + machine.succeed("test -e /.swapvol/swapfile"); ''; }