mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
refactor(youko): disable HDD spindown from a udev rule
Apply hdparm -B 255 -S 0 whenever a disk appears, which also covers the re-add after a bridge reset, instead of a boot oneshot plus an hourly timer. Drop -J 0: hdparm has always aborted it without --please-destroy-my-drive, and wdidle3 already reads disabled on both disks (it is persistent firmware state). This was the last user of mylib.systemdHardening.privilegedOneshot, so remove the preset and its test group. Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
1 parent
f8ca25a03b
commit
8084f25e6f
4 files changed
+8
-110
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
mylib,
|
mylib,
|
||||||
myvars,
|
myvars,
|
||||||
@@ -13,6 +14,10 @@ let
|
|||||||
# disko config does (the /dev/sdX names are not stable).
|
# disko config does (the /dev/sdX names are not stable).
|
||||||
hddPublic = "/dev/disk/by-id/ata-WDC_WD40EJRX-89T1XY0_WD-WCC7K0XDCZE6";
|
hddPublic = "/dev/disk/by-id/ata-WDC_WD40EJRX-89T1XY0_WD-WCC7K0XDCZE6";
|
||||||
hddEncrypted = "/dev/disk/by-id/ata-WDC_WD40EZRZ-22GXCB0_WD-WCC7K7VV9613";
|
hddEncrypted = "/dev/disk/by-id/ata-WDC_WD40EZRZ-22GXCB0_WD-WCC7K7VV9613";
|
||||||
|
hddSerials = lib.concatMapStringsSep "|" (lib.removePrefix "/dev/disk/by-id/ata-") [
|
||||||
|
hddPublic
|
||||||
|
hddEncrypted
|
||||||
|
];
|
||||||
|
|
||||||
coreModule = mylib.genVmHostModule {
|
coreModule = mylib.genVmHostModule {
|
||||||
inherit pkgs hostName;
|
inherit pkgs hostName;
|
||||||
@@ -105,48 +110,13 @@ in
|
|||||||
];
|
];
|
||||||
|
|
||||||
# Keep the bridge powered: a suspended device is what most often triggers a
|
# Keep the bridge powered: a suspended device is what most often triggers a
|
||||||
# reset on resume.
|
# reset on resume. Spindown is another trigger, so turn off APM/standby on the
|
||||||
|
# HDDs each time they appear (a bridge reset re-adds them).
|
||||||
services.udev.extraRules = ''
|
services.udev.extraRules = ''
|
||||||
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="152d", ATTR{idProduct}=="0567", TEST=="power/control", ATTR{power/control}="on"
|
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="152d", ATTR{idProduct}=="0567", TEST=="power/control", ATTR{power/control}="on"
|
||||||
|
ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="${hddSerials}", RUN+="${pkgs.hdparm}/bin/hdparm -B 255 -S 0 $devnode"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# A spindown/spinup is a common trigger for the bridge resetting, so disable
|
|
||||||
# APM/standby on the HDDs. sdb in particular has ~1M load cycles (WD
|
|
||||||
# Intellipark), so stopping the idle head-parking also saves its mechanism.
|
|
||||||
# Read the settings back into the journal, and re-assert them hourly: the
|
|
||||||
# bridge or the disk's own firmware can drop them.
|
|
||||||
systemd.services.hdd-no-spindown = {
|
|
||||||
description = "Disable APM/standby on the USB HDDs";
|
|
||||||
after = [ "local-fs.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
serviceConfig = mylib.systemdHardening.privilegedOneshot // {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
CapabilityBoundingSet = [ "CAP_SYS_RAWIO" ];
|
|
||||||
PrivateDevices = false;
|
|
||||||
DeviceAllow = [ "block-sd rw" ];
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
for d in ${hddPublic} ${hddEncrypted}; do
|
|
||||||
echo "== $d =="
|
|
||||||
# -B 255: APM off; -S 0: no standby timer; -J 0: WD idle3 (Intellipark) off
|
|
||||||
${pkgs.hdparm}/bin/hdparm -B 255 -S 0 -J 0 "$d" || true
|
|
||||||
${pkgs.hdparm}/bin/hdparm -B "$d" || true
|
|
||||||
${pkgs.hdparm}/bin/hdparm -J "$d" || true
|
|
||||||
${pkgs.hdparm}/bin/hdparm -C "$d" || true
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.hdd-no-spindown = {
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnBootSec = "10min";
|
|
||||||
OnUnitActiveSec = "1h";
|
|
||||||
Persistent = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Watch the disks with SMART. UDMA_CRC_Error_Count growth is the early warning
|
# Watch the disks with SMART. UDMA_CRC_Error_Count growth is the early warning
|
||||||
# for the bridge/link problem.
|
# for the bridge/link problem.
|
||||||
services.smartd = {
|
services.smartd = {
|
||||||
|
|||||||
@@ -42,37 +42,6 @@ rec {
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# For short-lived root oneshots that perform one narrowly scoped privileged
|
|
||||||
# operation. Callers add only the capabilities and device access they need.
|
|
||||||
# ProtectKernelTunables is deliberately unset because it makes /sys read-only.
|
|
||||||
privilegedOneshot = {
|
|
||||||
AmbientCapabilities = "";
|
|
||||||
CapabilityBoundingSet = "";
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
PrivateNetwork = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RemoveIPC = true;
|
|
||||||
RestrictAddressFamilies = [ "AF_UNIX" ];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
UMask = "0077";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Apply a preset at mkOptionDefault priority, so nixpkgs module values win.
|
# Apply a preset at mkOptionDefault priority, so nixpkgs module values win.
|
||||||
mkDefaults = lib.mapAttrs (_: lib.mkOptionDefault);
|
mkDefaults = lib.mapAttrs (_: lib.mkOptionDefault);
|
||||||
}
|
}
|
||||||
@@ -9,17 +9,6 @@ let
|
|||||||
"~@clock @cpu-emulation @debug @module @mount @obsolete @privileged @raw-io @reboot @swap"
|
"~@clock @cpu-emulation @debug @module @mount @obsolete @privileged @raw-io @reboot @swap"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
privilegedOneshot = {
|
|
||||||
CapabilityBoundingSet = "";
|
|
||||||
DeviceAllow = null;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
PrivateNetwork = true;
|
|
||||||
ProtectKernelTunables = null;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [ "AF_UNIX" ];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Only 80/443.
|
# Only 80/443.
|
||||||
@@ -32,12 +21,4 @@ in
|
|||||||
whisper-asr = sandbox // {
|
whisper-asr = sandbox // {
|
||||||
PrivateDevices = false;
|
PrivateDevices = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
privilegedOneshot = {
|
|
||||||
hdd-no-spindown = privilegedOneshot // {
|
|
||||||
CapabilityBoundingSet = [ "CAP_SYS_RAWIO" ];
|
|
||||||
DeviceAllow = [ "block-sd rw" ];
|
|
||||||
PrivateDevices = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
@@ -12,23 +12,6 @@ let
|
|||||||
lib.genAttrs names (
|
lib.genAttrs names (
|
||||||
n: lib.getAttrs keys outputs.nixosConfigurations.${host}.config.systemd.services.${n}.serviceConfig
|
n: lib.getAttrs keys outputs.nixosConfigurations.${host}.config.systemd.services.${n}.serviceConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
privilegedKeys = [
|
|
||||||
"CapabilityBoundingSet"
|
|
||||||
"DeviceAllow"
|
|
||||||
"NoNewPrivileges"
|
|
||||||
"PrivateDevices"
|
|
||||||
"PrivateNetwork"
|
|
||||||
"ProtectKernelTunables"
|
|
||||||
"ProtectSystem"
|
|
||||||
"RestrictAddressFamilies"
|
|
||||||
];
|
|
||||||
privilegedUnit =
|
|
||||||
host: name:
|
|
||||||
let
|
|
||||||
cfg = outputs.nixosConfigurations.${host}.config.systemd.services.${name}.serviceConfig;
|
|
||||||
in
|
|
||||||
lib.genAttrs privilegedKeys (key: cfg.${key} or null);
|
|
||||||
in
|
in
|
||||||
units "youko" [
|
units "youko" [
|
||||||
"caddy"
|
"caddy"
|
||||||
@@ -36,8 +19,3 @@ units "youko" [
|
|||||||
"vmalert-homelab"
|
"vmalert-homelab"
|
||||||
]
|
]
|
||||||
// units "aquamarine" [ "whisper-asr" ]
|
// units "aquamarine" [ "whisper-asr" ]
|
||||||
// {
|
|
||||||
privilegedOneshot = {
|
|
||||||
hdd-no-spindown = privilegedUnit "youko" "hdd-no-spindown";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user