hardware:jednodeskove-pocitace:espressobin:uspavani-rotacniho-hdd-pomoci-hdparm

Espressobin: uspávání rotačního HDD pomocí hdparm

Vytvořeno: 8.6.2020

Poznámka k aktuálnosti: Toto je dobový článek. Postup vychází z konkrétního nasazení na Espressobinu s Nextcloudem a nemusí odpovídat dnešnímu stavu systemd, NextcloudPi ani nástrojů kolem storage.

Důležité: Tento článek se týká klasického rotačního HDD. Pro SSD a NVMe se podobné uspávání přes hdparm běžně nepoužívá.

hdparm umožňuje nastavit standby režim rotačního disku. V mém případě šlo o HDD připojený k Espressobinu, kde jsem chtěl snížit hlučnost a zbytečné opotřebení mechaniky. Samotné nastavení ale komplikovalo několik souběžných problémů: Advanced Power Management, procesy probouzející disk a nepřesnosti při sledování /proc/diskstats.

Uspání po 30 minutách idle času odpovídalo hodnotě -S 241:

hdparm -S 241 /dev/sda

Okamžité uspání disku:

hdparm -y /dev/sda

Pro sledování stavu se hodilo průběžné ověřování:

while : ; do /sbin/hdparm -C /dev/sda; sleep 1; done

Nebo:

watch -n 1 hdparm -C /dev/sda

Později jsem zjistil důležitou věc: dotaz hdparm -C /dev/sda mění statistiky v /proc/diskstats, takže může rušit vlastní logiku pro vyhodnocení nečinnosti disku.

Na některých systémech stačilo použít jen -S. Na Espressobinu se disk neuspával vůbec, takže jsem zkoušel i Advanced Power Management přes parametr -B.

Například:

hdparm -B 127 /dev/sda

Nebo kombinaci:

hdparm -B 50 -S 241 /dev/sda

V praxi se ale uspávání chovalo nevyzpytatelně. Disk se někdy neuspal vůbec a jindy usínal dřív, než jsem čekal. Na této cestě jsem nakonec rezignoval.

Nakonec se mi osvědčilo nečekat, že se disk bude uspávat jen podle interní logiky hdparm, ale pravidelně kontrolovat změny v /proc/diskstats a při nečinnosti ručně spustit hdparm -y.

Původní jednodušší verze skriptu:

#!/bin/bash
 
# Get new state from diskstats
devcode=$(findfs UUID=hFAc5i-yMtV-UC83-jF99-UnqA-ck7f-qYlnzo | cut -c 6-8)
 
NEWstate=$(cat /proc/diskstats | grep $devcode)
echo $NEWstate > /run/diskNEWstate.txt
 
# compare md5 sums
md5new=$(md5sum /run/diskNEWstate.txt | sed 's/ .*//')
md5old=$(md5sum /run/diskOLDstate.txt | sed 's/ .*//')
 
# if no changes, power down
if [ "$md5new" = "$md5old" ]; then
        hdparm -y /dev/disk/by-id/ata-ST4000VN008-2DR166_ZDH8BP5S
        echo "going to sleep"
fi
 
# Write current state to file
echo $NEWstate > /run/diskOLDstate.txt

Skript byl spouštěný přes cron každých 30 minut. Když se obsah /proc/diskstats od minulého běhu nezměnil, disk se uspal.

Později jsem zjistil, že i u uspaného disku se mění některé sloupce v /proc/diskstats. Proto jsem skript rozšířil o odstranění sloupců, které nemělo smysl sledovat:

#!/bin/bash
 
# Get new state from diskstats
devcode=$(findfs UUID=hFAc5i-yMtV-UC83-jF99-UnqA-ck7f-qYlnzo | cut -c 6-8)
 
NEWstate=$(cat /proc/diskstats | grep $devcode)
 
del_column () {
       NEWstate=$(echo $NEWstate | sed -r 's/(\s+)?\S+//'$1)
}
 
del_column 14
del_column 13
del_column 7
del_column 6
del_column 4
 
echo $NEWstate > /run/diskNEWstate.txt
 
# compare md5 sums
md5new=$(md5sum /run/diskNEWstate.txt | sed 's/ .*//')
md5old=$(md5sum /run/diskOLDstate.txt | sed 's/ .*//')
 
# if no changes, power down
if [ "$md5new" = "$md5old" ]; then
       hdparm -y /dev/disk/by-id/ata-ST4000VN008-2DR166_ZDH8BP5S
       echo "going to sleep"
else
       #if changes
       date >> /etc/scripts/sleep.log
fi
 
# Write current state to file
echo $NEWstate > /run/diskOLDstate.txt

Pokud se použije čistě hdparm, je dobré pamatovat na to, že nastavení po restartu mizí. U systemd systému jsem to tehdy řešil přes vlastní službu:

# /usr/lib/systemd/system/sda-spindown.service
[Unit]
Description=Set HDD spindown

[Service]
Type=oneshot
ExecStart=/sbin/hdparm -B 241 /dev/sdb
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Aktivace služby:

systemctl daemon-reload
systemctl enable sda-spindown.service
systemctl start sda-spindown.service

Nejvíc času zabralo hledání procesů, které disk probouzely. V mém případě šlo hlavně o údržbu Nextcloudu a monitoring stavu disku v NextcloudPi.

První krok bylo omezit frekvenci Nextcloud cronu. Místo každých 15 minut jsem ho nechal běžet jen jednou denně:

crontab -e -u www-data
12 10 * * * php -f /var/www/nextcloud/cron.php

Druhý problém byl v NextcloudPi: zapnutá volba automatického monitoringu zdraví HDD probouzela disk prakticky pořád. Tuto volbu jsem vypnul.

nextcloud-hdd-health-monitor.jpg

  • hardware/jednodeskove-pocitace/espressobin/uspavani-rotacniho-hdd-pomoci-hdparm.txt
  • Poslední úprava: 23.04.2026 11:48
  • autor: Petr Nosek