Unverified Commit da64ac6b authored by 7c6f434c's avatar 7c6f434c Committed by GitHub
Browse files

Merge pull request #310807 from Naxdy/work/improve-btrfs-autoscrub

nixos/btrfs: refactor & improve device selection for autoScrub
parents db9f79b8 d0239a1e
Loading
Loading
Loading
Loading
+28 −10
Original line number Diff line number Diff line
{ config, lib, pkgs, utils, ... }:

with lib;

let
  inherit (lib)
    mkEnableOption
    mkOption
    types
    mkMerge
    mkIf
    optionals
    mkDefault
    nameValuePair
    listToAttrs
    filterAttrs
    mapAttrsToList
    foldl';

  inInitrd = config.boot.initrd.supportedFilesystems.btrfs or false;
  inSystem = config.boot.supportedFilesystems.btrfs or false;
@@ -27,8 +38,9 @@ in
        description = ''
          List of paths to btrfs filesystems to regularly call {command}`btrfs scrub` 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.
          Note that if you have filesystems that span multiple devices (e.g. RAID), you should
          take care to use the same device for any given mount point and let btrfs take care
          of automatically mounting the rest, in order to avoid scrubbing the same data multiple times.
        '';
      };

@@ -97,12 +109,18 @@ in
        }
      ];

      # 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));
      # This will remove duplicated units from either having a filesystem mounted multiple
      # time, or additionally mounted subvolumes, as well as having a filesystem span
      # multiple devices (provided the same device is used to mount said filesystem).
      services.btrfs.autoScrub.fileSystems =
      let
        isDeviceInList = list: device: builtins.filter (e: e.device == device) list != [ ];

        uniqueDeviceList = foldl' (acc: e: if isDeviceInList acc e.device then acc else acc ++ [ e ]) [ ];
      in
      mkDefault (map (e: e.mountPoint)
        (uniqueDeviceList (mapAttrsToList (name: fs: { mountPoint = fs.mountPoint; device = fs.device; })
          (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,