about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/tasks/filesystems
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/tasks/filesystems')
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix65
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix132
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/cifs.nix25
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix14
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/exfat.nix11
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/ext.nix22
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/f2fs.nix25
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/glusterfs.nix11
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/jfs.nix19
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/nfs.nix108
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/ntfs.nix11
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/reiserfs.nix25
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix32
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/vboxsf.nix23
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/vfat.nix25
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/xfs.nix29
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/zfs.nix546
17 files changed, 1123 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
new file mode 100644
index 000000000000..5fda24adb978
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
@@ -0,0 +1,65 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+
+  bootFs = filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems;
+
+  commonFunctions = ''
+    prompt() {
+        local name="$1"
+        printf "enter passphrase for $name: "
+    }
+    tryUnlock() {
+        local name="$1"
+        local path="$2"
+        if bcachefs unlock -c $path > /dev/null 2> /dev/null; then    # test for encryption
+            prompt $name
+            until bcachefs unlock $path 2> /dev/null; do              # repeat until sucessfully unlocked
+                printf "unlocking failed!\n"
+                prompt $name
+            done
+            printf "unlocking successful.\n"
+        fi
+    }
+  '';
+
+  openCommand = name: fs:
+    let
+      # we need only unlock one device manually, and cannot pass multiple at once
+      # remove this adaptation when bcachefs implements mounting by filesystem uuid
+      # also, implement automatic waiting for the constituent devices when that happens
+      # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
+      firstDevice = head (splitString ":" fs.device);
+    in
+      ''
+        tryUnlock ${name} ${firstDevice}
+      '';
+
+in
+
+{
+  config = mkIf (elem "bcachefs" config.boot.supportedFilesystems) (mkMerge [
+    {
+      system.fsPackages = [ pkgs.bcachefs-tools ];
+
+      # use kernel package with bcachefs support until it's in mainline
+      boot.kernelPackages = pkgs.linuxPackages_testing_bcachefs;
+    }
+
+    (mkIf ((elem "bcachefs" config.boot.initrd.supportedFilesystems) || (bootFs != {})) {
+      # the cryptographic modules are required only for decryption attempts
+      boot.initrd.availableKernelModules = [ "bcachefs" "chacha20" "poly1305" ];
+
+      boot.initrd.extraUtilsCommands = ''
+        copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/bcachefs
+      '';
+      boot.initrd.extraUtilsCommandsTest = ''
+        $out/bin/bcachefs version
+      '';
+
+      boot.initrd.postDeviceCommands = commonFunctions + concatStrings (mapAttrsToList openCommand bootFs);
+    })
+  ]);
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
new file mode 100644
index 000000000000..48be18c71021
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
@@ -0,0 +1,132 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "btrfs") config.boot.initrd.supportedFilesystems;
+  inSystem = any (fs: fs == "btrfs") config.boot.supportedFilesystems;
+
+  cfgScrub = config.services.btrfs.autoScrub;
+
+  enableAutoScrub = cfgScrub.enable;
+  enableBtrfs = inInitrd || inSystem || enableAutoScrub;
+
+in
+
+{
+  options = {
+    # One could also do regular btrfs balances, but that shouldn't be necessary
+    # during normal usage and as long as the filesystems aren't filled near capacity
+    services.btrfs.autoScrub = {
+      enable = mkEnableOption "regular btrfs scrub";
+
+      fileSystems = mkOption {
+        type = types.listOf types.path;
+        example = [ "/" ];
+        description = ''
+          List of paths to btrfs filesystems to regularily call <command>btrfs scrub</command> on.
+          Defaults to all mount points with btrfs filesystems.
+          If you mount a filesystem multiple times or additionally mount subvolumes,
+          you need to manually specify this list to avoid scrubbing multiple times.
+        '';
+      };
+
+      interval = mkOption {
+        default = "monthly";
+        type = types.str;
+        example = "weekly";
+        description = ''
+          Systemd calendar expression for when to scrub btrfs filesystems.
+          The recommended period is a month but could be less
+          (<citerefentry><refentrytitle>btrfs-scrub</refentrytitle>
+          <manvolnum>8</manvolnum></citerefentry>).
+          See
+          <citerefentry><refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>7</manvolnum></citerefentry>
+          for more information on the syntax.
+        '';
+      };
+
+    };
+  };
+
+  config = mkMerge [
+    (mkIf enableBtrfs {
+      system.fsPackages = [ pkgs.btrfs-progs ];
+
+      boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" "crc32c" ];
+
+      boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfs
+        ln -sv btrfs $out/bin/btrfsck
+        ln -sv btrfsck $out/bin/fsck.btrfs
+      '';
+
+      boot.initrd.extraUtilsCommandsTest = mkIf inInitrd
+      ''
+        $out/bin/btrfs --version
+      '';
+
+      boot.initrd.postDeviceCommands = mkIf inInitrd
+      ''
+        btrfs device scan
+      '';
+    })
+
+    (mkIf enableAutoScrub {
+      assertions = [
+        {
+          assertion = cfgScrub.enable -> (cfgScrub.fileSystems != []);
+          message = ''
+            If 'services.btrfs.autoScrub' is enabled, you need to have at least one
+            btrfs file system mounted via 'fileSystems' or specify a list manually
+            in 'services.btrfs.autoScrub.fileSystems'.
+          '';
+        }
+      ];
+
+      # This will yield duplicated units if the user mounts a filesystem multiple times
+      # or additionally mounts subvolumes, but going the other way around via devices would
+      # yield duplicated units when a filesystem spans multiple devices.
+      # This way around seems like the more sensible default.
+      services.btrfs.autoScrub.fileSystems = mkDefault (mapAttrsToList (name: fs: fs.mountPoint)
+      (filterAttrs (name: fs: fs.fsType == "btrfs") config.fileSystems));
+
+      # TODO: Did not manage to do it via the usual btrfs-scrub@.timer/.service
+      # template units due to problems enabling the parameterized units,
+      # so settled with many units and templating via nix for now.
+      # https://github.com/NixOS/nixpkgs/pull/32496#discussion_r156527544
+      systemd.timers = let
+        scrubTimer = fs: let
+          fs' = utils.escapeSystemdPath fs;
+        in nameValuePair "btrfs-scrub-${fs'}" {
+          description = "regular btrfs scrub timer on ${fs}";
+
+          wantedBy = [ "timers.target" ];
+          timerConfig = {
+            OnCalendar = cfgScrub.interval;
+            AccuracySec = "1d";
+            Persistent = true;
+          };
+        };
+      in listToAttrs (map scrubTimer cfgScrub.fileSystems);
+
+      systemd.services = let
+        scrubService = fs: let
+          fs' = utils.escapeSystemdPath fs;
+        in nameValuePair "btrfs-scrub-${fs'}" {
+          description = "btrfs scrub on ${fs}";
+
+          serviceConfig = {
+            Type = "oneshot";
+            Nice = 19;
+            IOSchedulingClass = "idle";
+            ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B ${fs}";
+          };
+        };
+      in listToAttrs (map scrubService cfgScrub.fileSystems);
+    })
+  ];
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/cifs.nix b/nixpkgs/nixos/modules/tasks/filesystems/cifs.nix
new file mode 100644
index 000000000000..47ba0c03c563
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/cifs.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "cifs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = {
+
+    system.fsPackages = mkIf (any (fs: fs == "cifs") config.boot.supportedFilesystems) [ pkgs.cifs-utils ];
+
+    boot.initrd.availableKernelModules = mkIf inInitrd
+      [ "cifs" "nls_utf8" "hmac" "md4" "ecb" "des_generic" "sha256" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        copy_bin_and_libs ${pkgs.cifs-utils}/sbin/mount.cifs
+      '';
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix
new file mode 100644
index 000000000000..12a407cabbfb
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/ecryptfs.nix
@@ -0,0 +1,14 @@
+{ config, lib, pkgs, ... }:
+# TODO: make ecryptfs work in initramfs?
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "ecryptfs") config.boot.supportedFilesystems) {
+    system.fsPackages = [ pkgs.ecryptfs ];
+    security.wrappers = {
+      "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
+      "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/exfat.nix b/nixpkgs/nixos/modules/tasks/filesystems/exfat.nix
new file mode 100644
index 000000000000..1527f993fdd4
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/exfat.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "exfat") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.exfat ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/ext.nix b/nixpkgs/nixos/modules/tasks/filesystems/ext.nix
new file mode 100644
index 000000000000..a14a3ac38549
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/ext.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+{
+  config = {
+
+    system.fsPackages = [ pkgs.e2fsprogs ];
+
+    # As of kernel 4.3, there is no separate ext3 driver (they're also handled by ext4.ko)
+    boot.initrd.availableKernelModules = [ "ext2" "ext4" ];
+
+    boot.initrd.extraUtilsCommands =
+      ''
+        # Copy e2fsck and friends.
+        copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/e2fsck
+        copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/tune2fs
+        ln -sv e2fsck $out/bin/fsck.ext2
+        ln -sv e2fsck $out/bin/fsck.ext3
+        ln -sv e2fsck $out/bin/fsck.ext4
+      '';
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/f2fs.nix b/nixpkgs/nixos/modules/tasks/filesystems/f2fs.nix
new file mode 100644
index 000000000000..a305235979a2
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/f2fs.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  inInitrd = any (fs: fs == "f2fs") config.boot.initrd.supportedFilesystems;
+  fileSystems = filter (x: x.fsType == "f2fs") config.system.build.fileSystems;
+in
+{
+  config = mkIf (any (fs: fs == "f2fs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.f2fs-tools ];
+
+    boot.initrd.availableKernelModules = mkIf inInitrd [ "f2fs" "crc32" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd ''
+      copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs
+      ${optionalString (any (fs: fs.autoResize) fileSystems) ''
+        # We need f2fs-tools' tools to resize filesystems
+        copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/resize.f2fs
+      ''}
+
+    '';
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/glusterfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/glusterfs.nix
new file mode 100644
index 000000000000..e8c7fa8efbae
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/glusterfs.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "glusterfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.glusterfs ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/jfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/jfs.nix
new file mode 100644
index 000000000000..fc3905c7dc20
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/jfs.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inInitrd = any (fs: fs == "jfs") config.boot.initrd.supportedFilesystems;
+in
+{
+  config = mkIf (any (fs: fs == "jfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.jfsutils ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd ''
+      copy_bin_and_libs ${pkgs.jfsutils}/sbin/fsck.jfs
+    '';
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix
new file mode 100644
index 000000000000..d3a558738f4b
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix
@@ -0,0 +1,108 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "nfs") config.boot.initrd.supportedFilesystems;
+
+  nfsStateDir = "/var/lib/nfs";
+
+  rpcMountpoint = "${nfsStateDir}/rpc_pipefs";
+
+  idmapdConfFile = pkgs.writeText "idmapd.conf" ''
+    [General]
+    Pipefs-Directory = ${rpcMountpoint}
+    ${optionalString (config.networking.domain != null)
+      "Domain = ${config.networking.domain}"}
+
+    [Mapping]
+    Nobody-User = nobody
+    Nobody-Group = nogroup
+
+    [Translation]
+    Method = nsswitch
+  '';
+
+  nfsConfFile = pkgs.writeText "nfs.conf" cfg.extraConfig;
+
+  cfg = config.services.nfs;
+
+in
+
+{
+  ###### interface
+
+  options = {
+    services.nfs = {
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra nfs-utils configuration.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {
+
+    services.rpcbind.enable = true;
+
+    system.fsPackages = [ pkgs.nfs-utils ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
+
+    systemd.packages = [ pkgs.nfs-utils ];
+    systemd.generator-packages = [ pkgs.nfs-utils ];
+
+    environment.etc = {
+      "idmapd.conf".source = idmapdConfFile;
+      "nfs.conf".source = nfsConfFile;
+    };
+
+    systemd.services.nfs-blkmap =
+      { restartTriggers = [ nfsConfFile ];
+      };
+
+    systemd.targets.nfs-client =
+      { wantedBy = [ "multi-user.target" "remote-fs.target" ];
+      };
+
+    systemd.services.nfs-idmapd =
+      { restartTriggers = [ idmapdConfFile ];
+      };
+
+    systemd.services.nfs-mountd =
+      { restartTriggers = [ nfsConfFile ];
+        enable = mkDefault false;
+      };
+
+    systemd.services.nfs-server =
+      { restartTriggers = [ nfsConfFile ];
+        enable = mkDefault false;
+      };
+
+    systemd.services.auth-rpcgss-module =
+      {
+        unitConfig.ConditionPathExists = [ "" "/etc/krb5.keytab" ];
+      };
+
+    systemd.services.rpc-gssd =
+      { restartTriggers = [ nfsConfFile ];
+        unitConfig.ConditionPathExists = [ "" "/etc/krb5.keytab" ];
+      };
+
+    systemd.services.rpc-statd =
+      { restartTriggers = [ nfsConfFile ];
+
+        preStart =
+          ''
+            mkdir -p /var/lib/nfs/{sm,sm.bak}
+          '';
+      };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/ntfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/ntfs.nix
new file mode 100644
index 000000000000..c40d2a1a80bc
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/ntfs.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = mkIf (any (fs: fs == "ntfs" || fs == "ntfs-3g") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.ntfs3g ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/reiserfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/reiserfs.nix
new file mode 100644
index 000000000000..ab4c43e2ab82
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/reiserfs.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "reiserfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "reiserfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.reiserfsprogs ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "reiserfs" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        copy_bin_and_libs ${pkgs.reiserfsprogs}/sbin/reiserfsck
+        ln -s reiserfsck $out/bin/fsck.reiserfs
+      '';
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix b/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix
new file mode 100644
index 000000000000..1dcc4c87e3ce
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix
@@ -0,0 +1,32 @@
+{ config, pkgs, lib, ... }:
+
+{
+  config = lib.mkMerge [
+
+    (lib.mkIf (lib.any (fs: fs == "unionfs-fuse") config.boot.initrd.supportedFilesystems) {
+      boot.initrd.kernelModules = [ "fuse" ];
+
+      boot.initrd.extraUtilsCommands = ''
+        copy_bin_and_libs ${pkgs.fuse}/sbin/mount.fuse
+        copy_bin_and_libs ${pkgs.unionfs-fuse}/bin/unionfs
+        substitute ${pkgs.unionfs-fuse}/sbin/mount.unionfs-fuse $out/bin/mount.unionfs-fuse \
+          --replace '${pkgs.bash}/bin/bash' /bin/sh \
+          --replace '${pkgs.fuse}/sbin' /bin \
+          --replace '${pkgs.unionfs-fuse}/bin' /bin
+        chmod +x $out/bin/mount.unionfs-fuse
+      '';
+
+      boot.initrd.postDeviceCommands = ''
+          # Hacky!!! fuse hard-codes the path to mount
+          mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
+          ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
+          ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
+        '';
+    })
+
+    (lib.mkIf (lib.any (fs: fs == "unionfs-fuse") config.boot.supportedFilesystems) {
+      system.fsPackages = [ pkgs.unionfs-fuse ];
+    })
+
+  ];
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/vboxsf.nix b/nixpkgs/nixos/modules/tasks/filesystems/vboxsf.nix
new file mode 100644
index 000000000000..5497194f6a8d
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/vboxsf.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "vboxsf") config.boot.initrd.supportedFilesystems;
+
+  package = pkgs.runCommand "mount.vboxsf" { preferLocalBuild = true; } ''
+    mkdir -p $out/bin
+    cp ${pkgs.linuxPackages.virtualboxGuestAdditions}/bin/mount.vboxsf $out/bin
+  '';
+in
+
+{
+  config = mkIf (any (fs: fs == "vboxsf") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ package ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "vboxsf" ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/vfat.nix b/nixpkgs/nixos/modules/tasks/filesystems/vfat.nix
new file mode 100644
index 000000000000..958e27ae8a32
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/vfat.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "vfat") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "vfat") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.dosfstools ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "vfat" "nls_cp437" "nls_iso8859-1" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        copy_bin_and_libs ${pkgs.dosfstools}/sbin/dosfsck
+        ln -sv dosfsck $out/bin/fsck.vfat
+      '';
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix
new file mode 100644
index 000000000000..c6a90bcf1a51
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "xfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "xfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.xfsprogs.bin ];
+
+    boot.initrd.availableKernelModules = mkIf inInitrd [ "xfs" "crc32c" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        copy_bin_and_libs ${pkgs.xfsprogs.bin}/bin/fsck.xfs
+      '';
+
+    # Trick just to set 'sh' after the extraUtils nuke-refs.
+    boot.initrd.extraUtilsCommandsTest = mkIf inInitrd
+      ''
+        sed -i -e 's,^#!.*,#!'$out/bin/sh, $out/bin/fsck.xfs
+      '';
+  };
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
new file mode 100644
index 000000000000..37a19fb9fc8c
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
@@ -0,0 +1,546 @@
+{ config, lib, pkgs, utils, ... }:
+#
+# todo:
+#   - crontab for scrubs, etc
+#   - zfs tunables
+
+with utils;
+with lib;
+
+let
+
+  cfgZfs = config.boot.zfs;
+  cfgSnapshots = config.services.zfs.autoSnapshot;
+  cfgSnapFlags = cfgSnapshots.flags;
+  cfgScrub = config.services.zfs.autoScrub;
+
+  inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems;
+  inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems;
+
+  enableAutoSnapshots = cfgSnapshots.enable;
+  enableAutoScrub = cfgScrub.enable;
+  enableZfs = inInitrd || inSystem || enableAutoSnapshots || enableAutoScrub;
+
+  kernel = config.boot.kernelPackages;
+
+  packages = if config.boot.zfs.enableUnstable then {
+    spl = null;
+    zfs = kernel.zfsUnstable;
+    zfsUser = pkgs.zfsUnstable;
+  } else {
+    spl = kernel.spl;
+    zfs = kernel.zfs;
+    zfsUser = pkgs.zfs;
+  };
+
+  autosnapPkg = pkgs.zfstools.override {
+    zfs = packages.zfsUser;
+  };
+
+  zfsAutoSnap = "${autosnapPkg}/bin/zfs-auto-snapshot";
+
+  datasetToPool = x: elemAt (splitString "/" x) 0;
+
+  fsToPool = fs: datasetToPool fs.device;
+
+  zfsFilesystems = filter (x: x.fsType == "zfs") config.system.build.fileSystems;
+
+  allPools = unique ((map fsToPool zfsFilesystems) ++ cfgZfs.extraPools);
+
+  rootPools = unique (map fsToPool (filter fsNeededForBoot zfsFilesystems));
+
+  dataPools = unique (filter (pool: !(elem pool rootPools)) allPools);
+
+  snapshotNames = [ "frequent" "hourly" "daily" "weekly" "monthly" ];
+
+  # When importing ZFS pools, there's one difficulty: These scripts may run
+  # before the backing devices (physical HDDs, etc.) of the pool have been
+  # scanned and initialized.
+  #
+  # An attempted import with all devices missing will just fail, and can be
+  # retried, but an import where e.g. two out of three disks in a three-way
+  # mirror are missing, will succeed. This is a problem: When the missing disks
+  # are later discovered, they won't be automatically set online, rendering the
+  # pool redundancy-less (and far slower) until such time as the system reboots.
+  #
+  # The solution is the below. poolReady checks the status of an un-imported
+  # pool, to see if *every* device is available -- in which case the pool will be
+  # in state ONLINE, as opposed to DEGRADED, FAULTED or MISSING.
+  #
+  # The import scripts then loop over this, waiting until the pool is ready or a
+  # sufficient amount of time has passed that we can assume it won't be. In the
+  # latter case it makes one last attempt at importing, allowing the system to
+  # (eventually) boot even with a degraded pool.
+  importLib = {zpoolCmd, awkCmd, cfgZfs}: ''
+    poolReady() {
+      pool="$1"
+      state="$("${zpoolCmd}" import 2>/dev/null | "${awkCmd}" "/pool: $pool/ { found = 1 }; /state:/ { if (found == 1) { print \$2; exit } }; END { if (found == 0) { print \"MISSING\" } }")"
+      if [[ "$state" = "ONLINE" ]]; then
+        return 0
+      else
+        echo "Pool $pool in state $state, waiting"
+        return 1
+      fi
+    }
+    poolImported() {
+      pool="$1"
+      "${zpoolCmd}" list "$pool" >/dev/null 2>/dev/null
+    }
+    poolImport() {
+      pool="$1"
+      "${zpoolCmd}" import -d "${cfgZfs.devNodes}" -N $ZFS_FORCE "$pool"
+    }
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+    boot.zfs = {
+      enableUnstable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Use the unstable zfs package. This might be an option, if the latest
+          kernel is not yet supported by a published release of ZFS. Enabling
+          this option will install a development version of ZFS on Linux. The
+          version will have already passed an extensive test suite, but it is
+          more likely to hit an undiscovered bug compared to running a released
+          version of ZFS on Linux.
+          '';
+      };
+
+      extraPools = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "tank" "data" ];
+        description = ''
+          Name or GUID of extra ZFS pools that you wish to import during boot.
+
+          Usually this is not necessary. Instead, you should set the mountpoint property
+          of ZFS filesystems to <literal>legacy</literal> and add the ZFS filesystems to
+          NixOS's <option>fileSystems</option> option, which makes NixOS automatically
+          import the associated pool.
+
+          However, in some cases (e.g. if you have many filesystems) it may be preferable
+          to exclusively use ZFS commands to manage filesystems. If so, since NixOS/systemd
+          will not be managing those filesystems, you will need to specify the ZFS pool here
+          so that NixOS automatically imports it on every boot.
+        '';
+      };
+
+      devNodes = mkOption {
+        type = types.path;
+        default = "/dev/disk/by-id";
+        example = "/dev/disk/by-id";
+        description = ''
+          Name of directory from which to import ZFS devices.
+
+          This should be a path under /dev containing stable names for all devices needed, as
+          import may fail if device nodes are renamed concurrently with a device failing.
+        '';
+      };
+
+      forceImportRoot = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Forcibly import the ZFS root pool(s) during early boot.
+
+          This is enabled by default for backwards compatibility purposes, but it is highly
+          recommended to disable this option, as it bypasses some of the safeguards ZFS uses
+          to protect your ZFS pools.
+
+          If you set this option to <literal>false</literal> and NixOS subsequently fails to
+          boot because it cannot import the root pool, you should boot with the
+          <literal>zfs_force=1</literal> option as a kernel parameter (e.g. by manually
+          editing the kernel params in grub during boot). You should only need to do this
+          once.
+        '';
+      };
+
+      forceImportAll = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Forcibly import all ZFS pool(s).
+
+          This is enabled by default for backwards compatibility purposes, but it is highly
+          recommended to disable this option, as it bypasses some of the safeguards ZFS uses
+          to protect your ZFS pools.
+
+          If you set this option to <literal>false</literal> and NixOS subsequently fails to
+          import your non-root ZFS pool(s), you should manually import each pool with
+          "zpool import -f &lt;pool-name&gt;", and then reboot. You should only need to do
+          this once.
+        '';
+      };
+
+      requestEncryptionCredentials = mkOption {
+        type = types.bool;
+        default = config.boot.zfs.enableUnstable;
+        description = ''
+          Request encryption keys or passwords for all encrypted datasets on import.
+          Dataset encryption is only supported in zfsUnstable at the moment.
+          For root pools the encryption key can be supplied via both an
+          interactive prompt (keylocation=prompt) and from a file
+          (keylocation=file://). Note that for data pools the encryption key can
+          be only loaded from a file and not via interactive prompt since the
+          import is processed in a background systemd service.
+        '';
+      };
+
+    };
+
+    services.zfs.autoSnapshot = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service.
+          Note that you must set the <literal>com.sun:auto-snapshot</literal>
+          property to <literal>true</literal> on all datasets which you wish
+          to auto-snapshot.
+
+          You can override a child dataset to use, or not use auto-snapshotting
+          by setting its flag with the given interval:
+          <literal>zfs set com.sun:auto-snapshot:weekly=false DATASET</literal>
+        '';
+      };
+
+      flags = mkOption {
+        default = "-k -p";
+        example = "-k -p --utc";
+        type = types.str;
+        description = ''
+          Flags to pass to the zfs-auto-snapshot command.
+
+          Run <literal>zfs-auto-snapshot</literal> (without any arguments) to
+          see available flags.
+
+          If it's not too inconvenient for snapshots to have timestamps in UTC,
+          it is suggested that you append <literal>--utc</literal> to the list
+          of default options (see example).
+
+          Otherwise, snapshot names can cause name conflicts or apparent time
+          reversals due to daylight savings, timezone or other date/time changes.
+        '';
+      };
+
+      frequent = mkOption {
+        default = 4;
+        type = types.int;
+        description = ''
+          Number of frequent (15-minute) auto-snapshots that you wish to keep.
+        '';
+      };
+
+      hourly = mkOption {
+        default = 24;
+        type = types.int;
+        description = ''
+          Number of hourly auto-snapshots that you wish to keep.
+        '';
+      };
+
+      daily = mkOption {
+        default = 7;
+        type = types.int;
+        description = ''
+          Number of daily auto-snapshots that you wish to keep.
+        '';
+      };
+
+      weekly = mkOption {
+        default = 4;
+        type = types.int;
+        description = ''
+          Number of weekly auto-snapshots that you wish to keep.
+        '';
+      };
+
+      monthly = mkOption {
+        default = 12;
+        type = types.int;
+        description = ''
+          Number of monthly auto-snapshots that you wish to keep.
+        '';
+      };
+    };
+
+    services.zfs.autoScrub = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enables periodic scrubbing of ZFS pools.
+        '';
+      };
+
+      interval = mkOption {
+        default = "Sun, 02:00";
+        type = types.str;
+        example = "daily";
+        description = ''
+          Systemd calendar expression when to scrub ZFS pools. See
+          <citerefentry><refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>7</manvolnum></citerefentry>.
+        '';
+      };
+
+      pools = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        example = [ "tank" ];
+        description = ''
+          List of ZFS pools to periodically scrub. If empty, all pools
+          will be scrubbed.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkMerge [
+    (mkIf enableZfs {
+      assertions = [
+        {
+          assertion = config.networking.hostId != null;
+          message = "ZFS requires networking.hostId to be set";
+        }
+        {
+          assertion = !cfgZfs.forceImportAll || cfgZfs.forceImportRoot;
+          message = "If you enable boot.zfs.forceImportAll, you must also enable boot.zfs.forceImportRoot";
+        }
+        {
+          assertion = cfgZfs.requestEncryptionCredentials -> cfgZfs.enableUnstable;
+          message = "This feature is only available for zfs unstable. Set the NixOS option boot.zfs.enableUnstable.";
+        }
+      ];
+
+      virtualisation.lxd.zfsSupport = true;
+
+      boot = {
+        kernelModules = [ "zfs" ] ++ optional (!cfgZfs.enableUnstable) "spl";
+        extraModulePackages = with packages; [ zfs ] ++ optional (!cfgZfs.enableUnstable) spl;
+      };
+
+      boot.initrd = mkIf inInitrd {
+        kernelModules = [ "zfs" ] ++ optional (!cfgZfs.enableUnstable) "spl";
+        extraUtilsCommands =
+          ''
+            copy_bin_and_libs ${packages.zfsUser}/sbin/zfs
+            copy_bin_and_libs ${packages.zfsUser}/sbin/zdb
+            copy_bin_and_libs ${packages.zfsUser}/sbin/zpool
+          '';
+        extraUtilsCommandsTest = mkIf inInitrd
+          ''
+            $out/bin/zfs --help >/dev/null 2>&1
+            $out/bin/zpool --help >/dev/null 2>&1
+          '';
+        postDeviceCommands = concatStringsSep "\n" ([''
+            ZFS_FORCE="${optionalString cfgZfs.forceImportRoot "-f"}"
+
+            for o in $(cat /proc/cmdline); do
+              case $o in
+                zfs_force|zfs_force=1)
+                  ZFS_FORCE="-f"
+                  ;;
+              esac
+            done
+          ''] ++ [(importLib {
+            # See comments at importLib definition.
+            zpoolCmd = "zpool";
+            awkCmd = "awk";
+            inherit cfgZfs;
+          })] ++ (map (pool: ''
+            echo -n "importing root ZFS pool \"${pool}\"..."
+            # Loop across the import until it succeeds, because the devices needed may not be discovered yet.
+            if ! poolImported "${pool}"; then
+              for trial in `seq 1 60`; do
+                poolReady "${pool}" > /dev/null && msg="$(poolImport "${pool}" 2>&1)" && break
+                sleep 1
+                echo -n .
+              done
+              echo
+              if [[ -n "$msg" ]]; then
+                echo "$msg";
+              fi
+              poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool.
+            fi
+            ${lib.optionalString cfgZfs.requestEncryptionCredentials ''
+              zfs load-key -a
+            ''}
+        '') rootPools));
+      };
+
+      boot.loader.grub = mkIf inInitrd {
+        zfsSupport = true;
+      };
+
+      environment.etc."zfs/zed.d".source = "${packages.zfsUser}/etc/zfs/zed.d/";
+
+      system.fsPackages = [ packages.zfsUser ]; # XXX: needed? zfs doesn't have (need) a fsck
+      environment.systemPackages = [ packages.zfsUser ]
+        ++ optional enableAutoSnapshots autosnapPkg; # so the user can run the command to see flags
+
+      services.udev.packages = [ packages.zfsUser ]; # to hook zvol naming, etc.
+      systemd.packages = [ packages.zfsUser ];
+
+      systemd.services = let
+        getPoolFilesystems = pool:
+          filter (x: x.fsType == "zfs" && (fsToPool x) == pool) config.system.build.fileSystems;
+
+        getPoolMounts = pool:
+          let
+            mountPoint = fs: escapeSystemdPath fs.mountPoint;
+          in
+            map (x: "${mountPoint x}.mount") (getPoolFilesystems pool);
+
+        createImportService = pool:
+          nameValuePair "zfs-import-${pool}" {
+            description = "Import ZFS pool \"${pool}\"";
+            requires = [ "systemd-udev-settle.service" ];
+            after = [ "systemd-udev-settle.service" "systemd-modules-load.service" ];
+            wantedBy = (getPoolMounts pool) ++ [ "local-fs.target" ];
+            before = (getPoolMounts pool) ++ [ "local-fs.target" ];
+            unitConfig = {
+              DefaultDependencies = "no";
+            };
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = true;
+            };
+            script = (importLib {
+              # See comments at importLib definition.
+              zpoolCmd="${packages.zfsUser}/sbin/zpool";
+              awkCmd="${pkgs.gawk}/bin/awk";
+              inherit cfgZfs;
+            }) + ''
+              poolImported "${pool}" && exit
+              echo -n "importing ZFS pool \"${pool}\"..."
+              # Loop across the import until it succeeds, because the devices needed may not be discovered yet.
+              for trial in `seq 1 60`; do
+                poolReady "${pool}" && poolImport "${pool}" && break
+                sleep 1
+              done
+              poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool.
+              if poolImported "${pool}"; then
+                ${optionalString cfgZfs.requestEncryptionCredentials "\"${packages.zfsUser}/sbin/zfs\" load-key -r \"${pool}\""}
+                echo "Successfully imported ${pool}"
+              else
+                exit 1
+              fi
+            '';
+          };
+
+        # This forces a sync of any ZFS pools prior to poweroff, even if they're set
+        # to sync=disabled.
+        createSyncService = pool:
+          nameValuePair "zfs-sync-${pool}" {
+            description = "Sync ZFS pool \"${pool}\"";
+            wantedBy = [ "shutdown.target" ];
+            unitConfig = {
+              DefaultDependencies = false;
+            };
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = true;
+            };
+            script = ''
+              ${packages.zfsUser}/sbin/zfs set nixos:shutdown-time="$(date)" "${pool}"
+            '';
+          };
+        createZfsService = serv:
+          nameValuePair serv {
+            after = [ "systemd-modules-load.service" ];
+            wantedBy = [ "zfs.target" ];
+          };
+
+      in listToAttrs (map createImportService dataPools ++
+                      map createSyncService allPools ++
+                      map createZfsService [ "zfs-mount" "zfs-share" "zfs-zed" ]);
+
+      systemd.targets."zfs-import" =
+        let
+          services = map (pool: "zfs-import-${pool}.service") dataPools;
+        in
+          {
+            requires = services;
+            after = services;
+            wantedBy = [ "zfs.target" ];
+          };
+
+      systemd.targets."zfs".wantedBy = [ "multi-user.target" ];
+    })
+
+    (mkIf enableAutoSnapshots {
+      systemd.services = let
+                           descr = name: if name == "frequent" then "15 mins"
+                                    else if name == "hourly" then "hour"
+                                    else if name == "daily" then "day"
+                                    else if name == "weekly" then "week"
+                                    else if name == "monthly" then "month"
+                                    else throw "unknown snapshot name";
+                           numSnapshots = name: builtins.getAttr name cfgSnapshots;
+                         in builtins.listToAttrs (map (snapName:
+                              {
+                                name = "zfs-snapshot-${snapName}";
+                                value = {
+                                  description = "ZFS auto-snapshotting every ${descr snapName}";
+                                  after = [ "zfs-import.target" ];
+                                  serviceConfig = {
+                                    Type = "oneshot";
+                                    ExecStart = "${zfsAutoSnap} ${cfgSnapFlags} ${snapName} ${toString (numSnapshots snapName)}";
+                                  };
+                                  restartIfChanged = false;
+                                };
+                              }) snapshotNames);
+
+      systemd.timers = let
+                         timer = name: if name == "frequent" then "*:0,15,30,45" else name;
+                       in builtins.listToAttrs (map (snapName:
+                            {
+                              name = "zfs-snapshot-${snapName}";
+                              value = {
+                                wantedBy = [ "timers.target" ];
+                                timerConfig = {
+                                  OnCalendar = timer snapName;
+                                  Persistent = "yes";
+                                };
+                              };
+                            }) snapshotNames);
+    })
+
+    (mkIf enableAutoScrub {
+      systemd.services.zfs-scrub = {
+        description = "ZFS pools scrubbing";
+        after = [ "zfs-import.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+        };
+        script = ''
+          ${packages.zfsUser}/bin/zpool scrub ${
+            if cfgScrub.pools != [] then
+              (concatStringsSep " " cfgScrub.pools)
+            else
+              "$(${packages.zfsUser}/bin/zpool list -H -o name)"
+            }
+        '';
+      };
+
+      systemd.timers.zfs-scrub = {
+        wantedBy = [ "timers.target" ];
+        after = [ "multi-user.target" ]; # Apparently scrubbing before boot is complete hangs the system? #53583
+        timerConfig = {
+          OnCalendar = cfgScrub.interval;
+          Persistent = "yes";
+        };
+      };
+    })
+  ];
+}