diff --git a/modules/hardware.nix b/modules/hardware.nix index e2cdbf6..f0ba280 100644 --- a/modules/hardware.nix +++ b/modules/hardware.nix @@ -23,13 +23,48 @@ hardware.enableRedistributableFirmware = true; # HDD I/O tuning for torrent seeding workload (high-concurrency random reads). + # # mq-deadline sorts requests into elevator sweeps, reducing seek distance. # Aggressive deadlines (15s) let the scheduler accumulate more ops before dispatching, # maximizing coalescence — latency is irrelevant since torrent peers tolerate 30-60s. # fifo_batch=128 keeps sweeps long; writes_starved=16 heavily favors reads. # 4 MiB readahead matches libtorrent piece extent affinity for sequential prefetch. - services.udev.extraRules = '' - ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="mq-deadline", ATTR{queue/read_ahead_kb}="4096", ATTR{queue/nr_requests}="512" - ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ENV{ID_ATA_ROTATION_RATE_RPM}!="0", RUN+="${pkgs.bash}/bin/bash -c 'echo 15000 > /sys$devpath/queue/iosched/read_expire; echo 15000 > /sys$devpath/queue/iosched/write_expire; echo 128 > /sys$devpath/queue/iosched/fifo_batch; echo 16 > /sys$devpath/queue/iosched/writes_starved; echo 4096 > /sys$devpath/queue/max_sectors_kb 2>/dev/null || true'" - ''; + # + # This runs as a systemd oneshot rather than udev rules because the NixOS ZFS module + # hardcodes a udev rule that forces scheduler="none" on all ZFS member partitions' + # parent disks, overriding any scheduler set via udev on the disk event. + systemd.services.hdd-io-tuning = { + description = "HDD I/O scheduler and queue tuning"; + after = [ + "zfs-import.target" + "systemd-udev-settle.service" + ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + for dev in /sys/block/sd*; do + [ -f "$dev/queue/rotational" ] || continue + [ "$(cat "$dev/queue/rotational")" = "1" ] || continue + + # skip removable devices (USB sticks report removable=1) + [ "$(cat "$dev/removable")" = "0" ] || continue + + echo mq-deadline > "$dev/queue/scheduler" + echo 4096 > "$dev/queue/read_ahead_kb" + echo 512 > "$dev/queue/nr_requests" + + echo 15000 > "$dev/queue/iosched/read_expire" + echo 15000 > "$dev/queue/iosched/write_expire" + echo 128 > "$dev/queue/iosched/fifo_batch" + echo 16 > "$dev/queue/iosched/writes_starved" + + echo 4096 > "$dev/queue/max_sectors_kb" 2>/dev/null || true + + echo "Tuned $(basename "$dev"): mq-deadline, 4M readahead, 15s deadlines" + done + ''; + }; }