Disable disk spindown on NixOS
I have two disks in my homelab NAS that would spin down when idle, which puts unnecessary strain on the drives as they are typically woken up again a few minutes later. Disabling this is not very hard, and this pattern is usable for other cases where you want systemd to run multiple instances of something. While all examples below uses NixOS syntax, it’s all just standard systemd components at play.
I initially tried asking a LLM on how to do it and was just provided with a broken, impossible solution so I thought I might as well write this up if someone else needs something similar.
Table of Contents
Overview
We will create a new systemd target, which specifies what units it
requires, and these units will be instance units that runs a bash
script that will run a simple bash script that disables disk spindown
using hdparm
.
┌─────────┐ ┌─────────────────────────┐ ┌──────────────────────────────┐
│ │ │ │ │ │
│ systemd ├────►│ disable-spindown.target ├────►│ disable-spindown@sda.service │
│ │ │ │ │ │
└─────────┘ └────────────┬────────────┘ └──────────────────────────────┘
│
│
│
│ ┌──────────────────────────────┐
│ │ │
└─────────────────►│ disable-spindown@sdb.service │
│ │
└──────────────────────────────┘
(mermaid-ascii.art is great, but I should really make my hugo build my mermaid charts automagically)
Script
The actual script is really simple – it just runs hdparm
on a given
disk. Below I’ve wrapped it in some nix but it should be simple to
understand:
{ lib, pkgs, ... }:
let
disableSpindownScript = pkgs.writeShellScript "disable-spindown.sh" ''
${pkgs.hdparm}/bin/hdparm -B 255 -S 0 /dev/$1
'';
disableSpindownDisks = [
"sda"
"sdb"
];
in
{
# the rest of the file goes here...
}
I’ve also added a list of disks to disable spindown for, which we’ll use later on.
systemd bits
First we create a systemd.target(5) which depends on our
instance units, which will run said units on boot. Then we create a
systemd.service(5) unit which will run the script per disk.
Each disk will get it’s own disable-spindown@sda.service
,
disable-spindown@sdb.service
et c
systemd.targets."disable-spindown" = {
wantedBy = [ "multi-user.target" ];
wants = map (i: "disable-spindown@${i}.service") disableSpindownDisks;
};
systemd.services."disable-spindown@" = {
description = "Disable spindown for disk";
wantedBy = [ "multi-users.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${disableSpindownScript} %i";
};
};
Just update disableSpindownDisks
to change which disks to disable
spindown for, and a new unit will spin up on boot (and after
rebuilding if it’s a new disk added).
Conclusion
This pattern can probably be abstracted and reused, but I will probably just copy/paste it where needed as it’s just a few lines. While it might seem overkill for running a bash oneliner (and yes, it is for this case!) the pattern is simple and reusable for other, similar situations.