174 lines
5.9 KiB
Nix
174 lines
5.9 KiB
Nix
{ lib, config, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.roles.btrfs;
|
|
in
|
|
{
|
|
options.roles.btrfs = {
|
|
enable = mkEnableOption "Enable btrfs filesystem management";
|
|
|
|
filesystems = mkOption {
|
|
type = types.attrsOf (types.submodule {
|
|
options = {
|
|
# Filesystem-level maintenance options
|
|
scrub = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = "Enable automatic scrubbing for this filesystem";
|
|
};
|
|
interval = mkOption {
|
|
type = types.str;
|
|
default = "weekly";
|
|
description = "Scrub interval (systemd timer format)";
|
|
};
|
|
};
|
|
deduplication = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Enable beesd deduplication for this filesystem";
|
|
};
|
|
hashTableSizeMB = mkOption {
|
|
type = types.int;
|
|
default = 1024;
|
|
description = "Hash table size in MB (should be multiple of 16)";
|
|
};
|
|
verbosity = mkOption {
|
|
type = types.str;
|
|
default = "info";
|
|
description = "Logging verbosity level";
|
|
};
|
|
};
|
|
balance = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Enable periodic balance operations";
|
|
};
|
|
interval = mkOption {
|
|
type = types.str;
|
|
default = "monthly";
|
|
description = "Balance interval (systemd timer format)";
|
|
};
|
|
dataUsage = mkOption {
|
|
type = types.int;
|
|
default = 50;
|
|
description = "Data usage threshold for balance";
|
|
};
|
|
metadataUsage = mkOption {
|
|
type = types.int;
|
|
default = 50;
|
|
description = "Metadata usage threshold for balance";
|
|
};
|
|
};
|
|
|
|
# Mountpoint-based configuration
|
|
mountpoints = mkOption {
|
|
type = types.attrsOf (types.submodule {
|
|
options = {
|
|
subvolume = mkOption {
|
|
type = types.nullOr types.str;
|
|
default = null;
|
|
description = "Subvolume name. If null, uses default subvolume.";
|
|
};
|
|
compression = mkOption {
|
|
type = types.str;
|
|
default = "zstd";
|
|
description = "Compression algorithm (zstd, lzo, lz4, none)";
|
|
};
|
|
autodefrag = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Enable automatic defragmentation";
|
|
};
|
|
extraOptions = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [];
|
|
description = "Additional mount options";
|
|
};
|
|
};
|
|
});
|
|
default = {};
|
|
description = "Mountpoint configurations for this filesystem";
|
|
};
|
|
};
|
|
});
|
|
default = {};
|
|
description = "Btrfs filesystems configuration";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
environment.systemPackages = with pkgs; [
|
|
btrfs-progs
|
|
compsize
|
|
];
|
|
|
|
# Generate fileSystems configuration from mountpoints
|
|
fileSystems = mkMerge (flatten (mapAttrsToList (device: fsCfg:
|
|
mapAttrsToList (mountpoint: mountCfg:
|
|
{
|
|
${mountpoint} = {
|
|
device = device;
|
|
fsType = "btrfs";
|
|
options =
|
|
(optional (mountCfg.subvolume != null) "subvol=${mountCfg.subvolume}") ++
|
|
[ "compress=${mountCfg.compression}" ] ++
|
|
(optional mountCfg.autodefrag "autodefrag") ++
|
|
mountCfg.extraOptions;
|
|
};
|
|
}
|
|
) fsCfg.mountpoints
|
|
) cfg.filesystems));
|
|
|
|
# Configure scrub service using NixOS built-in
|
|
services.btrfs.autoScrub = mkIf (any (fs: fs.scrub.enable) (attrValues cfg.filesystems)) {
|
|
enable = true;
|
|
interval = "weekly"; # TODO: Make this configurable per filesystem
|
|
fileSystems = attrNames (filterAttrs (_: fs: fs.scrub.enable) cfg.filesystems);
|
|
};
|
|
|
|
# Configure beesd for filesystems with deduplication enabled
|
|
services.beesd.filesystems = mapAttrs' (device: fsCfg:
|
|
nameValuePair (replaceStrings ["/"] ["_"] (replaceStrings ["-"] ["_"] device)) {
|
|
spec = device;
|
|
hashTableSizeMB = fsCfg.deduplication.hashTableSizeMB;
|
|
verbosity = fsCfg.deduplication.verbosity;
|
|
}
|
|
) (filterAttrs (_: fs: fs.deduplication.enable) cfg.filesystems);
|
|
|
|
# Custom balance services for filesystems with balance enabled
|
|
systemd.services = mkMerge (mapAttrsToList (device: fsCfg: mkIf fsCfg.balance.enable {
|
|
"btrfs-balance-${replaceStrings ["/"] ["-"] (replaceStrings ["-"] ["_"] device)}" = {
|
|
description = "Balance btrfs filesystem ${device}";
|
|
script = ''
|
|
${pkgs.btrfs-progs}/bin/btrfs balance start \
|
|
-dusage=${toString fsCfg.balance.dataUsage} \
|
|
-musage=${toString fsCfg.balance.metadataUsage} \
|
|
${device}
|
|
'';
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
Nice = 19;
|
|
IOSchedulingClass = "idle";
|
|
};
|
|
};
|
|
}) cfg.filesystems);
|
|
|
|
# Balance timers
|
|
systemd.timers = mkMerge (mapAttrsToList (device: fsCfg: mkIf fsCfg.balance.enable {
|
|
"btrfs-balance-${replaceStrings ["/"] ["-"] (replaceStrings ["-"] ["_"] device)}" = {
|
|
description = "Periodic balance for ${device}";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnCalendar = fsCfg.balance.interval;
|
|
Persistent = true;
|
|
};
|
|
};
|
|
}) cfg.filesystems);
|
|
};
|
|
}
|