ThinkRoot

bine ați navigat pe insula mea de pe internet

Se demonta HDD-ul extern atașat la NUC

De două ori în același număr de săptămâni, m-am trezit cu Nextcloud inaccesibil și cu un mesaj de eroare despre directorul de date invalid. De fiecare dată, cauza era aceeași: HDD-ul extern pe care îl folosesc ca stocare principală pe thinkserver nu mai era montat.

Prima dată am crezut că am uitat să-l adaug în /etc/fstab. L-am montat manual, am adăugat intrarea corectă cu opțiunile defaults,nofail și am crezut că am rezolvat problema. La câteva zile distanță, același scenariu. De data aceasta era clar că ceva mai adânc nu funcționează cum trebuie.

Ce spuneau jurnalele

Am rulat sudo journalctl -b | grep -i "mnt\|sd\|fstab\|mount" și răspunsul a fost imediat. La ora 6:36 dimineața pe 4 aprilie, și din nou la 6:20 pe 9 aprilie, apăreau aceste mesaje în jurnal:

device offline error, dev sdb, sector 0 op 0x1:(WRITE)
EXT4-fs (sdb1): shut down requested (2)
Aborting journal on device sdb1-8.
systemd: Unmounting mnt-data.mount - /mnt/data...
systemd: mnt-data.mount: Deactivated successfully.

Kernelul detecta că device-ul a dispărut brusc în timp ce scria pe el, oprea jurnalul EXT4 ca să nu corupă datele, și demonta partiția în mod de urgență. HDD-ul se reconecta imediat după, dar cu un alt device name - sdb devenea sdc și invers - iar systemd nu îl remonta automat.

Problema nu era în fstab. Problema era că HDD-ul se deconecta fizic.

Cauza: USB autosuspend

HDD-ul este conectat printr-un adaptor USB-SATA cu chipset JMicron JMS578. Linux are o funcție numită USB autosuspend care pune device-urile USB în sleep după o perioadă de inactivitate pentru a economisi energie. Valoarea implicită pe acest sistem era de 2000 de milisecunde - adică 2 secunde de inactivitate erau suficiente pentru a suspenda adaptorul.

În timpul zilei, cu containere Docker care accesează constant datele de pe HDD, autosuspend-ul nu apuca să intre în acțiune. Dar noaptea, după ore de inactivitate, adaptorul intra în sleep și nu se trezea corect atunci când kernelul încerca să scrie pe el. Rezultatul era device offline error și demontarea de urgență.

Am confirmat că autosuspend-ul era activ cu:

for d in /sys/bus/usb/devices/*/idVendor; do
  vendor=$(cat $d)
  if [ "$vendor" = "152d" ]; then
    dir=$(dirname $d)
    echo "autosuspend_delay_ms: $(cat $dir/power/autosuspend_delay_ms)"
  fi
done

Rezultatul: autosuspend_delay_ms: 2000.

Rezolvarea

Soluția este să forțezi device-ul USB să rămână activ permanent prin setarea power/control la valoarea on:

for d in /sys/bus/usb/devices/*/idVendor; do
  vendor=$(cat $d)
  if [ "$vendor" = "152d" ]; then
    dir=$(dirname $d)
    echo on | sudo tee $dir/power/control
  fi
done

Cu control: on, valoarea autosuspend_delay_ms este ignorată complet, indiferent ce valoare are.

Pentru ca setarea să persiste după reboot, am creat o regulă udev:

sudo nano /etc/udev/rules.d/99-usb-hdd-nosuspend.rules

Cu conținutul:

ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="152d", ATTR{idProduct}=="0578", ATTR{power/autosuspend_delay_ms}="-1", ATTR{power/control}="on"

Valorile idVendor și idProduct le-am obținut din lsusb. Regula se aplică de fiecare dată când adaptorul este detectat de sistem, fie la boot, fie după o reconectare fizică.

Am reîncărcat regulile udev și am remontat HDD-ul:

sudo udevadm control --reload-rules
sudo mount -a

Ce am învățat

Un HDD extern conectat prin USB nu se comportă la fel ca unul intern conectat SATA. Kernelul îl tratează ca pe orice alt device USB și îi aplică politicile de economisire a energiei, indiferent că pe el rulează date critice pentru servicii. Opțiunea nofail din fstab este utilă - împiedică sistemul să se blocheze la boot dacă HDD-ul nu e disponibil - dar nu face nimic pentru a preveni demontarea în timpul funcționării.

Dacă folosești un HDD extern ca stocare pentru servicii self-hosted, autosuspend-ul USB este primul lucru pe care trebuie să-l dezactivezi.

⬅ The one before
De la Catedrală la Catacombe

Up next ➡
Franța renunță la Windows și trece pe Linux