diff --git a/NixOS.md b/NixOS.md index a0dd5f0..4567d74 100644 --- a/NixOS.md +++ b/NixOS.md @@ -236,6 +236,8 @@ nix-eval '{ a=false; }.a or true' #=> false nix-eval '{ a=1; }?a' #=> true +nix-eval 'with lib.strings; concatMapStrings (x: " -a " + x + " -i 600") ["sda" "sdc"]' +#=> " -a sda -i 600 -a sdc -i 600" ``` ## Escape strings diff --git a/hosts/yodaHedgehog/configuration.nix b/hosts/yodaHedgehog/configuration.nix index fff6be8..a6d3768 100644 --- a/hosts/yodaHedgehog/configuration.nix +++ b/hosts/yodaHedgehog/configuration.nix @@ -22,7 +22,8 @@ ../../modules/btrbk ./btrbk-config.nix ../../modules/de-p1st-monitor.nix - ../../modules/spin-down-hdd.nix + ../../modules/spin-down/hdparm.nix + ../../modules/spin-down/hd-idle.nix ../../modules/btrfs-scrub.nix ../../modules/btrfs-mount-options.nix @@ -32,6 +33,14 @@ boot.initrd.luks.devices."crypted".allowDiscards = true; yoda.btrfsFileSystems = ["/" "/mnt/backup"]; #yoda.btrfsMounts = yoda.btrfsFileSystems; + yoda.spin-down.hdparm = [ + # 6tb1 + "ata-WDC_WD60EFAX-68SHWN0_WD-WX31D29924PZ" + ]; + yoda.spin-down.hd-idle = [ + # 6tb2; not supported by hdparm / does not support setting idle timer + "ata-ST6000DM003-2CY186_ZR11WA9K" + ]; boot.kernelParams = []; boot.kernelPackages = pkgs.linuxPackages; diff --git a/hosts/yodaNas/configuration.nix b/hosts/yodaNas/configuration.nix index 9d5221c..daabc72 100644 --- a/hosts/yodaNas/configuration.nix +++ b/hosts/yodaNas/configuration.nix @@ -26,7 +26,8 @@ ./btrbk-config.nix ../../modules/netcup-dns.nix ../../modules/de-p1st-monitor.nix - ../../modules/spin-down-hdd.nix + ../../modules/spin-down/hdparm.nix + ../../modules/spin-down/hd-idle.nix ../../modules/btrfs-scrub.nix ../../modules/btrfs-mount-options.nix @@ -36,7 +37,7 @@ boot.initrd.luks.devices."luks-3d974bd0-f373-469b-8e9c-2d5516e9f0f5".allowDiscards = true; yoda.btrfsFileSystems = ["/" "/mnt/data" "/mnt/backup"]; #yoda.btrfsMounts = yoda.btrfsFileSystems; - yoda.spin-down-hdd = [ + yoda.spin-down.hdparm = [ # 4tb1 "ata-WDC_WD40EFRX-68N32N0_WD-WCC7K0CPF0N1" # 3tb1 @@ -44,6 +45,7 @@ # 3tb2 "ata-WDC_WD30EFRX-68EUZN0_WD-WMC4N0564095" ]; + yoda.spin-down.hd-idle = []; boot.kernelParams = [ # Microarchitectural Data Sampling (MDS), see https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html#mitigation-control-on-the-kernel-command-line diff --git a/modules/spin-down/hd-idle.nix b/modules/spin-down/hd-idle.nix new file mode 100644 index 0000000..3d3aebd --- /dev/null +++ b/modules/spin-down/hd-idle.nix @@ -0,0 +1,33 @@ +{ lib, config, options, pkgs, modulesPath, ... }: +with lib; +let + cfg = config.yoda.spin-down.hd-idle; +in +{ + options = { + yoda.spin-down.hd-idle = mkOption { + type = types.listOf types.str; + default = [ ]; + example = ["ata-ST6000DM003-2CY186_ZR11WA9K"]; + description = '' + List with IDs (/dev/disk/by-id/) of HDDs to spin down with hd-idle after 5 minutes. + + Please try to use yoda.spin-down.hdparm first. + ''; + }; + }; + + config = mkIf (length cfg > 0) { + systemd.services."hd-idle" = { + description = "Spin down inactive HDDs"; + wantedBy = [ "multi-user.target" ]; + script = + let + args = strings.concatMapStrings (x: " -a disk/by-id/${x} -i 300") cfg; + in '' + set -eu -o pipefail + ${pkgs.hd-idle}/bin/hd-idle ${args} + ''; + }; + }; +} diff --git a/modules/spin-down-hdd.nix b/modules/spin-down/hdparm.nix similarity index 85% rename from modules/spin-down-hdd.nix rename to modules/spin-down/hdparm.nix index f4117f6..b82a0ff 100644 --- a/modules/spin-down-hdd.nix +++ b/modules/spin-down/hdparm.nix @@ -16,7 +16,7 @@ # Get power status: # sudo hdparm -C /dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-WCC7K0CPF0N1 # #=> drive state is: active/idle -# + # Spin down after 2 minutes (120s/5s = 24). # TODO: Western Digital (WD) Red/Green drives don't work properly. For low `-S` values, they spin down after **10** minutes. And for high values they don't spin down at all. # - https://superuser.com/questions/1746074/spin-down-not-working-on-wd-red @@ -47,26 +47,34 @@ # See also: Systemd service to spin down after boot. https://wiki.archlinux.org/title/hdparm#Putting_a_drive_to_sleep_directly_after_boot -# TODO: For external (USB-)disks, use `hd-idle`. +# If a (external) disk does not supprot setting a timer with hdparm, use `hd-idle` instead. # https://www.reddit.com/r/NixOS/comments/751i5t/comment/do3f3l7/ # # Options: -# # -a : Select disk for subsequent parameters. +# # -a : Select disk for subsequent parameters. # # -i 120: Spin down after 2 minutes (120 seconds) of inactivity. -# ExecStart = "${pkgs.hd-idle}/bin/hd-idle -a /dev/disk/by-id/XXX-XXX-XXX -i 120"; +# ExecStart = "${pkgs.hd-idle}/bin/hd-idle -a disk/by-id/XXX-XXX-XXX -i 120"; + +# Example usage: +# sudo smartctl -i -n standby /dev/disk/by-id/ata-WDC_WD60EFAX-68SHWN0_WD-WX31D29924PZ | grep 'Power mode' +# #=> Power mode is: ACTIVE or IDLE +# sudo hd-idle -a disk/by-id/ata-WDC_WD60EFAX-68SHWN0_WD-WX31D29924PZ -i 120 { lib, config, options, pkgs, modulesPath, ... }: with lib; let - cfg = config.yoda.spin-down-hdd; + cfg = config.yoda.spin-down.hdparm; in { options = { - yoda.spin-down-hdd = mkOption { + yoda.spin-down.hdparm = mkOption { type = types.listOf types.str; default = [ ]; example = ["ata-WDC_WD40EFRX-68N32N0_WD-WCC7K0CPF0N1"]; description = '' - List with IDs (/dev/disk/by-id/) of HDDs to spin down after 10 minutes. + List with IDs (/dev/disk/by-id/) of HDDs to spin down with hdparm after 2-10 minutes. + + Not all HDDs (e.g. Seagate Barracuda ST600DM003) and many external disk enclosures don't support setting the idle timer. + In that case, please use yoda.spin-down.hd-idle for those disks instead. ''; }; };