zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit 444c8af1e46fcd52b2018256631a02349e38d735
parent 96fd5cba7081c68b18736c75065009ea3f458c53
Author: Katja (zaphyra) <git@ctu.cx>
Date: Mon, 2 Jun 2025 08:25:52 +0200

config/nixos/modules/filesystem/rootDisk: implement `zfs` support
1 file changed, 323 insertions(+), 198 deletions(-)
M
config/nixos/modules/filesystem/rootDisk.nix
|
521
+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
diff --git a/config/nixos/modules/filesystem/rootDisk.nix b/config/nixos/modules/filesystem/rootDisk.nix
@@ -1,5 +1,6 @@
 {
   povSelf,
+  hostConfig,
   config,
   lib,
   pkgs,

@@ -9,6 +10,11 @@
 let
   inherit (lib) types;
   cfg = lib.getAttrFromPath povSelf config;
+  users = (
+    config.modules.users
+    |> lib.mapAttrsToList (name: value: if value.enable then name else null)
+    |> lib.filter (element: !builtins.isNull element)
+  );
   part =
     name: content:
     if cfg.encrypt then

@@ -28,8 +34,8 @@ in
     };
     type = {
       type = types.enum [
-        "btrfs"
         "zfs"
+        "btrfs"
         "ext4"
       ];
     };

@@ -40,6 +46,32 @@ in
       type = types.bool;
       default = false;
     };
+    parts = {
+      home = {
+        type = types.bool;
+        default = false;
+      };
+      homePerUser = {
+        type = types.bool;
+        default = cfg.parts.home;
+      };
+      nix = {
+        type = types.bool;
+        default = true;
+      };
+      tmp = {
+        type = types.bool;
+        default = false;
+      };
+      system = {
+        type = types.bool;
+        default = false;
+      };
+    };
+    reservedSpace = {
+      type = types.str;
+      default = "8G";
+    };
     swap = {
       enable = {
         type = types.bool;

@@ -53,222 +85,315 @@ in
 
   config = lib.mkIf cfg.enable (
     lib.mkMerge [
-      (lib.mkIf (cfg.type == "btrfs") {
-        services.btrfs.autoScrub = {
-          enable = true;
-          interval = "weekly";
-        };
-      })
-      (lib.mkIf (cfg.type == "zfs") {
-        services.zfs.autoScrub.enable = true;
+      (
+        lib.mkIf (cfg.type == "zfs") {
+          assertions = [
+            {
+              assertion = cfg.parts.homePerUser -> cfg.parts.home;
+              message = "Option ${cfg}.parts.homePerUser requires ${cfg}.parts.home to be true.";
+            }
+          ];
 
-        boot = lib.mkIf cfg.encrypt {
-          initrd = {
-            luks.forceLuksSupportInInitrd = true;
-            supportedFilesystems = {
-              ext4 = true;
-            };
-            systemd.services.decrypt-root = {
-              description = "Decrypt ZFS root pool";
-              wantedBy = [ "initrd.target" ];
-              after = [ "zfs-import.target" ];
-              before = [
-                "create-needed-for-boot-dirs.service"
-                "defenestrate.service"
-                "sysroot.mount"
-              ];
-              onFailure = [ "emergency.target" ];
-              unitConfig.DefaultDependencies = "no";
-              serviceConfig = {
-                Type = "oneshot";
-                RemainAfterExit = "yes";
-              };
-              script = ''
-                systemd-cryptsetup attach key /dev/zvol/${config.networking.hostName}/key || exit 1
-                mount /dev/mapper/key /key --mkdir || exit 1
-                zfs load-key -a || exit 1
-                umount /key || exit 1
-                systemd-cryptsetup detach key || exit 1
-              '';
-            };
-          };
-          zfs = {
-            forceImportRoot = false;
-            allowHibernation = true;
-            requestEncryptionCredentials = false;
-          };
-        };
+          services.zfs.autoScrub.enable = true;
+
+          # katja: for some unknown reason userborn doesn't work when zfs is usded - needs to be investigated later
+          services.userborn.enable = lib.mkForce false;
 
-        disko.devices.zpool = {
-          ${config.networking.hostName} = {
-            type = "zpool";
-            options.ashift = "12";
-            rootFsOptions = lib.mkMerge [
-              {
-                acltype = "posixacl";
-                canmount = "off";
-                compression = "zstd-6";
-                mountpoint = "none";
-                xattr = "sa";
-              }
-              (lib.mkIf config.modules.filesystem.encrypt {
-                encryption = "on";
-                keyformat = "hex";
-                keylocation = "file:///key/${config.networking.hostName}.key";
-              })
-            ];
 
-            datasets = lib.mkMerge (
-              lib.flatten [
-                {
-                  data = {
-                    type = "zfs_fs";
-                    options.canmount = "off";
+          boot = lib.mkMerge [
+            (
+              lib.mkIf cfg.encrypt {
+                initrd = {
+                  luks.forceLuksSupportInInitrd = true;
+                  supportedFilesystems = {
+                    ext4 = true;
                   };
-                  "data/home" = {
-                    type = "zfs_fs";
-                    options = {
-                      canmount = "off";
-                      mountpoint = "none";
+                  systemd.services.decrypt-root = {
+                    description = "Decrypt ZFS root pool";
+                    wantedBy = [ "initrd.target" ];
+                    after = [ "zfs-import.target" ];
+                    before = [
+                      "create-needed-for-boot-dirs.service"
+                      "defenestrate.service"
+                      "sysroot.mount"
+                    ];
+                    onFailure = [ "emergency.target" ];
+                    unitConfig.DefaultDependencies = "no";
+                    serviceConfig = {
+                      Type = "oneshot";
+                      RemainAfterExit = "yes";
                     };
+                    script = ''
+                      systemd-cryptsetup attach key /dev/zvol/${hostConfig.hostName}/key || exit 1
+                      mount /dev/mapper/key /key --mkdir || exit 1
+                      zfs load-key -a || exit 1
+                      umount /key || exit 1
+                      systemd-cryptsetup detach key || exit 1
+                    '';
                   };
-                  "data/system" = {
-                    type = "zfs_fs";
-                    options.mountpoint = "legacy";
-                    mountpoint = "/nix/persist/system";
-                  };
-                  nix = {
-                    type = "zfs_fs";
-                    options = {
-                      atime = "off";
-                      mountpoint = "legacy";
+                };
+                zfs.requestEncryptionCredentials = false;
+              }
+            )
+            (
+              lib.mkIf hostConfig.hardware.allowHibernation {
+                zfs = {
+                  forceImportRoot = false;
+                  allowHibernation = true;
+                };
+              }
+            )
+          ];
+
+          fileSystems."/nix/persist" = lib.mkIf cfg.parts.system {
+            neededForBoot = true;
+          };
+
+          disko.devices = {
+            zpool = {
+              "${hostConfig.hostName}" = {
+                type = "zpool";
+                options.ashift = "12";
+                rootFsOptions = lib.mkMerge [
+                  {
+                    acltype = "posixacl";
+                    devices = "off";
+                    canmount = "off";
+                    compression = "zstd-6";
+                    exec = "off";
+                    mountpoint = "none";
+                    setuid = "off";
+                    xattr = "sa";
+                  }
+                  (
+                    lib.mkIf cfg.encrypt {
+                      encryption = "on";
+                      keyformat = "hex";
+                      keylocation = "file:///key/${hostConfig.hostName}.key";
+                    }
+                  )
+                ];
+                datasets = lib.mkMerge [
+                  {
+                    "reserved" = {
+                      type = "zfs_volume";
+                      size = cfg.reservedSpace;
+                      options.readonly = "on";
                     };
-                    mountpoint = "/nix";
-                  };
-                  os = {
-                    type = "zfs_fs";
-                    options.canmount = "off";
-                  };
-                  "os/nixos" = {
-                    type = "zfs_fs";
-                    options.canmount = "off";
-                  };
-                  "os/nixos/root-1" = {
-                    type = "zfs_fs";
-                    options = {
-                      atime = "off";
-                      compression = "zstd-fast";
-                      mountpoint = "legacy";
+                    "os" = {
+                      type = "zfs_fs";
+                      options.canmount = "off";
                     };
-                    mountpoint = "/";
-                  };
-                  reserved = {
-                    type = "zfs_volume";
-                    size = "8G";
-                    options.readonly = "on";
-                  };
-                }
-                (lib.mkIf config.modules.filesystem.encrypt {
-                  key = {
-                    type = "zfs_volume";
-                    size = "24M";
-                    options.encryption = "off";
-                    # TODO: luksFormat, add key and make readonly
-                  };
-                })
-                (lib.map (user: {
-                  "data/home/${user}" = {
-                    type = "zfs_fs";
-                    options.mountpoint = "legacy";
-                    mountOptions = [ "nofail" ];
-                    mountpoint =
-                      #                  if config.modules.filesystem.impermanence.persistHome then
-                      if true then "/home/${user}" else "/nix/persist/home/${user}";
-                  };
-                }) (lib.attrNames (lib.filterAttrs (name: value: value.enable == true) config.modules.users)))
-              ]
-            );
-          };
-        };
-      })
-      {
-        disko.devices.disk = {
-          ${config.networking.hostName} = {
-            type = "disk";
-            device = "${cfg.path}";
-            content = {
-              type = "gpt";
-              partitions = lib.mkMerge [
-                (lib.mkIf (config.modules.boot.type == "legacy") {
-                  grub-mbr = {
-                    size = "1M";
-                    type = "EF02";
-                    priority = 1;
-                  };
-                })
-                {
-                  boot = {
-                    type = lib.mkIf (config.modules.boot.type == "uefi") "EF00";
-                    size = "1G";
-                    content = {
-                      type = "filesystem";
-                      format = "vfat";
-                      mountOptions = [
-                        "nofail"
-                        "umask=0077"
-                        "dmask=0077"
-                      ];
-                      mountpoint = "/boot";
+                    "os/nixos" = {
+                      type = "zfs_fs";
+                      options.canmount = "off";
                     };
-                  };
-                }
-                {
-                  root.content = part "root" (
-                    lib.mkMerge [
-                      (lib.mkIf (cfg.type == "ext4") {
-                        type = "filesystem";
-                        format = "ext4";
-                        mountpoint = "/";
-                      })
-                      (lib.mkIf (cfg.type == "btrfs") {
-                        type = "btrfs";
-                        subvolumes = {
-                          "/nixos/@" = {
-                            mountpoint = "/";
-                          };
-                          "/nixos/@home" = {
-                            mountOptions = [ "compress=zstd" ];
-                            mountpoint = "/home";
-                          };
-                          "/nixos/@nix" = {
+                    "os/nixos/root-1" = {
+                      type = "zfs_fs";
+                      options.mountpoint = "legacy";
+                      mountpoint = "/";
+                    };
+                  }
+                  (
+                    lib.mkIf cfg.parts.nix {
+                      nix = {
+                        type = "zfs_fs";
+                        options = {
+                          atime = "off";
+                          devices = "off";
+                          exec = "on";
+                          mountpoint = "legacy";
+                        };
+                        mountpoint = "/nix";
+                      };
+                    }
+                  )
+                  (
+                    lib.mkIf (cfg.parts.system || cfg.parts.home) {
+                      data = {
+                        type = "zfs_fs";
+                        options.canmount = "off";
+                      };
+                    }
+                  )
+                  (
+                    lib.mkIf (cfg.parts.home && !cfg.parts.homePerUser) {
+                      "data/home" = {
+                        type = "zfs_fs";
+                        options.mountpoint = "legacy";
+                        mountpoint = "/home";
+                        mountOptions = [
+                          "nofail"
+                        ];
+                      };
+                    }
+                  )
+                  (
+                    lib.mkIf (cfg.parts.home && cfg.parts.homePerUser) {
+                      "data/home" = {
+                        type = "zfs_fs";
+                        options.canmount = "off";
+                      };
+                    }
+                  )
+                  (
+                    lib.mkIf cfg.parts.homePerUser (
+                      lib.listToAttrs (
+                        lib.map (user: {
+                          name = "data/home/${user}";
+                          value = {
+                            type = "zfs_fs";
+                            options = {
+                              devices = "off";
+                              mountpoint = "legacy";
+                              setuid = "off";
+                            };
                             mountOptions = [
-                              "compress=zstd"
-                              "noatime"
+                              "nofail"
                             ];
-                            mountpoint = "/nix";
+                            mountpoint = if config.modules.filesystem.impermanence.home.enable then "/nix/persist/home/${user}" else "/home/${user}";
                           };
+                        }) users
+                      )
+                    )
+                  )
+                  (
+                    lib.mkIf cfg.parts.system {
+                      "data/persist" = {
+                        type = "zfs_fs";
+                        options = {
+                          devices = "off";
+                          mountpoint = "legacy";
+                          setuid = "off";
                         };
-                      })
-                      (lib.mkIf (cfg.type == "zfs") {
-                        type = "zfs";
-                        pool = config.networking.hostName;
-                      })
-                    ]
-                  );
-                }
-                (
-                  if cfg.swap.enable then
-                    {
+                        mountpoint = "/nix/persist";
+                      };
+                    }
+                  )
+                  (
+                    lib.mkIf cfg.encrypt {
+                      key = {
+                        type = "zfs_volume";
+                        size = "50M";
+                        options.encryption = "off";
+                        # TODO: luksFormat, add key and make readonly
+                        # cryptsetup luksFormat /dev/zvol/<host>/key
+                        # cryptsetup open /dev/zvol/<host>/key key
+                        # mkfs.ext4 -O ^has_journal /dev/mapper/key
+                        # mount /dev/mapper/key /key
+                      };
+                    }
+                  )
+                ];
+              };
+            };
+          };
+        }
+      )
+      {
+        disko.devices = {
+          nodev = lib.mkIf cfg.parts.tmp {
+            "/tmp" = {
+              fsType = "tmpfs";
+              mountOptions = [
+                "nosuid"
+                "nodev"
+              ];
+            };
+          };
+          disk = {
+            # TODO: Add multidisk support
+            "${hostConfig.hostName}" = {
+              type = "disk";
+              device = "${cfg.path}";
+              content = {
+                type = "gpt";
+                partitions = lib.mkMerge [
+                  (lib.mkIf (config.modules.boot.type == "legacy") {
+                    grub-mbr = {
+                      size = "1M";
+                      type = "EF02";
+                      priority = 1;
+                    };
+                  })
+                  {
+                    boot = {
+                      size = "700M";
+                      content = {
+                        type = "filesystem";
+                        format = "vfat";
+                        mountOptions = [
+                          "nofail"
+                          "umask=0077"
+                          "dmask=0077"
+                        ];
+                        mountpoint = "/boot";
+                      };
+                    };
+                  }
+                  (
+                    lib.mkIf (config.modules.boot.type == "uefi") {
+                      boot.type = "EF00";
+                    }
+                  )
+
+                  {
+                    root.content = (
+                      lib.mkMerge [
+                        (
+                          lib.mkIf (cfg.type == "ext4") (
+                            part "root" {
+                              type = "filesystem";
+                              format = "ext4";
+                              mountpoint = "/";
+                            }
+                          )
+                        )
+                        (
+                          lib.mkIf (cfg.type == "btrfs") (
+                            part "root" {
+                              type = "btrfs";
+                              subvolumes = {
+                                "/nixos/@" = {
+                                  mountpoint = "/";
+                                };
+                                "/nixos/@home" = {
+                                  mountOptions = [ "compress=zstd" ];
+                                  mountpoint = "/home";
+                                };
+                                "/nixos/@nix" = {
+                                  mountOptions = [
+                                    "compress=zstd"
+                                    "noatime"
+                                  ];
+                                  mountpoint = "/nix";
+                                };
+                              };
+                            }
+                          )
+                        )
+                        (
+                          lib.mkIf (cfg.type == "zfs") {
+                            type = "zfs";
+                            pool = hostConfig.hostName;
+                          }
+                        )
+                      ]
+                    );
+                  }
+                  (
+                    if cfg.swap.enable then {
                       root.end = "-${cfg.swap.size}";
                       swap = {
                         size = "100%";
                         content = part "swap" { type = "swap"; };
                       };
+                    } else {
+                      root.size = "100%";
                     }
-                  else
-                    { root.size = "100%"; }
-                )
-              ];
+                  )
+                ];
+              };
             };
           };
         };