Poziv
Član moje obitelji živi u inozemstvu. Na polici stoji Raspberry Pi 5 s Home Assistantom, M.2 pločica, NVMe SSD, sve lijepo posloženo. SSH nije postavljen, jer mi nikad nije trebao. Nikakve mogućnosti da se samo svratim. Tisuću dvjesto kilometara neugodna je udaljenost za „pogledaj malo trepće li ona lampica”.
I onda taj poziv: sučelje više ne radi.
Otvorim log i vidim zid od jedne te iste linije, desetak i više puta zaredom:
sqlite3.OperationalError: unable to open database file
Jasan slučaj, pomislio sam. Recorder baza je otišla. Ta je dijagnoza bila potpuno kriva, a trebalo mi je dva dana da to primijetim. Log je bio svjedok koji je uvjerljivo iskazivao i pritom optužio pogrešnog.
Zašto baza podataka nije bila kriva
SQLite javlja ono što SQLite vidi: htio sam otvoriti datoteku, nije išlo. O uzroku poruka šuti, i tu je zamka. Pročitaš „database file” i pomisliš na pokvarenu bazu. Datoteka je bila sasvim u redu. Nestalo je tlo pod njom.
Datotečni sustav bio je montiran samo za čitanje. Read-only. Kernel je to sam odlučio, nakon što je disk bacio I/O grešku. ext4 za to ima dokumentiranu obradu grešaka, errors=remount-ro, i na golemoj većini sustava to je zadana postavka: čim disk prestane pouzdano odgovarati, Linux prestaje pisati. Zaštitni potez s jednostavnom logikom iza sebe. Bolje ne zapisati ništa nego zapisati glupost.
Za Home Assistant to ima ružnu posljedicu. Proces je i dalje radio. Živio je u RAM-u, obrađivao stanja, posluživao integracije, proizvodio greške. Jedino više nije mogao pisati. Ni recorder, ni restore_state, ni ponovno učitavanje konfiguracije, a u nekom trenutku ni uredna isporuka frontenda. Ono što je do mene stiglo kao „sučelje mrtvo, baza pokvarena” bio je sustav koji još govori, a više ništa ne može zapisati.
Ta zamjena teza prava je pouka cijelog slučaja. Read-only datotečni sustav javlja se u logovima kao problem s bazom. Ono što se zapravo dogodilo je hardverski signal koji tri sloja više dolazi u obliku aplikacijske greške.
Svejedno sam prvo poslušno odradio ono očito. Provjeriti bazu, htjeti je zamijeniti, proći recorder opcije. To je vrsta posla koja se doima produktivnom, a ne pomiče te ni milimetar. Gledano unatrag, trebalo mi je zasmetati što bazu nisam mogao ni obrisati. I to je bilo pisanje. Sustav mi je cijelo vrijeme pružao odgovor, a ja sam ga držao za poruku o grešci.
Upozorenje koje je pristajalo predobro
Nedugo prije toga sustav se ažurirao na Home Assistant OS 18. A u mojoj vlastitoj platformi stajalo je upozorenje, težina „izričito se ne preporučuje”, kategorija hardver, čiji se naslov čitao kao moj tiket:
RPi 5 with NVMe HAT: 18.0 makes the filesystem go read-only with endless I/O errors within minutes
Karticu sam pročitao tri puta. Raspberry Pi 5 na rpi5-64 imageu, NVMe na HAT pločici i, otprilike tri minute nakon nadogradnje na 18.0, uređaj je bio neupotrebljiv: neprekidne I/O greške, korijenski datotečni sustav premontiran u read-only, nužno odspajanje struje. Jedna rečenica iz upozorenja pogodila me posebno, jer sam preko tog istog efekta već bio zapeo: „Because the filesystem was already read-only, no logs survived the incident.” Netko je moju priču zapisao mjesecima prije nego što sam je proživio, uključujući i onaj dio o logu koji prestaje bilježiti.

U istom je popisu stajalo i drugo upozorenje za 18.0: žičani Ethernet link pada i vraća se svakih šest do deset sekundi, pripisano regresiji u macb driveru novog kernela 6.18, uz sučelje koje se ledi i integracije koje odlaze offline. Nekome čije sučelje baš nije dostupno i to zvuči prilično primamljivo.
Dakle, ono očito. Downgrade na 17.3. Išlo je na daljinu jer sam ažuriranja prethodno preuzeo i za svaki slučaj ih uploadao u vlastitu platformu, što se isplatilo baš u tom trenutku.
Problem je ostao. Isto, ista slika greške, samo s drugim brojem verzije u zaglavlju.
Na tom se mjestu teorija lomi, i to na detalju koji sam umalo preletio. Kod prijavitelja iz upozorenja povratak na drugi boot slot odmah je vratio stabilnost. Kod mene se kvar nakon downgradea jednostavno vratio. Isti simptom, ista mjera, drugačiji ishod: prvi tvrdi signal da jurim krivog počinitelja unatoč savršeno pristalom upozorenju.
Poštenja radi treba dodati da je upozorenje to samo iznijelo. Razina pouzdanosti bila je izričito označena kao niska: jedan jedini prijavitelj, jasstrong, issue #4785 u operating-system repozitoriju, bez komentara maintainera i bez analize uzroka. To sam pročitao, primio na znanje i zatim dva dana gurao u stranu, jer je teorija tako dobro pristajala.
To je prava zamka, a upozorenje tu nema nikakvu krivnju. Simptom ponekad ima više uzroka, a pogodak koji sjeda u redak ostaje hipoteza, samo dobro odjevena. Za nekoga s točno takvom kombinacijom, Pi 5 s NVMe pločicom i svjež na 18.0, upozorenje je i dalje ozbiljna stvar; onaj prijavitelj imao je ugrađen Samsung, dakle ništa jeftino. Moj slučaj to naprosto nije bio.
Takve slijepe ulice inače nestaju iz izvještaja o kvarovima bez riječi. Na kraju svatko svoju dijagnozu ispriča kao ravnu crtu, a kolege s istim problemom osjećaju se glupo kad dva dana vrte u krug. Barem me opovrgavanje odvelo dalje nego bilo kakva potvrda: od tog trenutka znao sam da se stvar odvija ispod operacijskog sustava.
Svjedok koji zašuti prerano
Proboj je stigao s mjesta gdje nisam očekivao baš ništa. Pogledao sam journal prethodnog boota, ono što izbaci journalctl -b -1. Čista bespomoćnost, jednostavno mi ništa pametnije više nije palo na pamet.
I tamo nije bilo ničega. Točnije: nešto je bilo, a onda je prestalo.
Zapis se prekidao usred rada. Bez gašenja, bez poruke o grešci, bez pozdrava. Posljednji vremenski žig bio je nekoliko sati prije grešaka koje je Home Assistant poslije prijavio. Log je završio dok je sustav dokazivo još radio.
Trebao mi je trenutak da shvatim što gledam. Log može završiti na dva načina: sustav se ugasi, ili sustav više ne može pisati. Prvo je otpalo, jer su nakon toga stizale poruke. Ostalo je dakle samo drugo. Od tog vremenskog žiga nadalje ni journald više nije uspijevao ništa spustiti na disk. Vlastiti zapisničar sustava, servis čiji je jedini posao bilježenje, zašutio je dok je sve ostalo teklo dalje.
To je najtvrđi dokaz u cijeloj ovoj priči, a sastoji se od odsutnosti. Ne od jednog unosa, nego od unosa koji nedostaju od jednog preciznog trenutka nadalje. Tko traži samo poruke o greškama, nikad ga neće naći. Treba gledati rupu.
Kad jednom to vidiš, sve se preslaguje. Desetci SQLite grešaka bili su kasni potres. Pravi se incident dogodio satima ranije, a jedini trag koji je ostavio jest točka na kojoj snimanje prestaje.
Detalj koji je već bio odgovor
Postojao je i drugi trag koji sam predugo otpisivao kao zanimljivost.
Uredan reboot nije pomagao. Sustav bi se digao, radio neko vrijeme i opet skliznuo u isto stanje. Tek kad bi se izvukao kabel, kad bi struja stvarno otišla i uređaj se ponovno upalio, nastupio bi mir na neko vrijeme.
Tu razliku treba shvatiti ozbiljno, jer je gotovo cijela dijagnoza. Softversko stanje, zaglavljeni proces, zaglavljeni mount, pun cache: ništa od toga ne preživi reboot. Kontroler u disku koji se zaglavio, preživi. Kod toplog restarta i dalje dobiva struju i svoje pokvareno stanje nosi preko. Kad pomaže isključivo odspajanje struje, problem nije u operacijskom sustavu. Ispod operacijskog sustava je.
Dva sam dana lovio softver dok je hardver svaki put stajao sa podignutom rukom i govorio: ja sam.
Počinitelj
Ugrađeni SSD bio je no-name model, NXM-256 u formatu 2242. Takvi su diskovi zapanjujuće jeftini, a kad se raspitaš zašto, razlog nađeš u tehničkom listu: MAXIO kontroler bez DRAM-a. Bez vlastitog cachea, agresivno optimiran na cijenu.
Ostalo je bio tužan mravlji posao. Pročitao sam recenzije proizvoda za točno taj model, i tamo je pisalo, više puta, od različitih ljudi, različitim riječima: ispadi, I/O greške, sustavi koji odu u read-only. Točno moja slika kvara, javno dostupna, mjesecima prije mog poziva.
To je najneugodniji dio ove priče. Odgovor je cijelo vrijeme stajao u polju za recenzije jedne internetske trgovine. Dvije zvjezdice, osrednji pravopis, stručno posve točno, a ja sam umjesto toga dva dana čitao logove.
Zamijenio sam ga s WD Green SN350. Ništa uzbudljivo, i namjerno ne najbrži model. Ono što se broji jest kontroler proizvođača koji na njega stavlja svoje ime i mala potrošnja. Drugo je na Pi 5 važnije: službena M.2 pločica isporučuje ograničenu snagu, a gladan potrošački NVMe pod opterećenjem ondje može upasti upravo u nestabilnost koju si htio izbjeći. Otada je mir.
Što mi je ovdje stvarno pomoglo, a što nije
Ovaj blog pišem za proizvod, pa otvoreno kažem koliki je bio njegov udio u priči.
Agent HA Fleet Managera ostao je dostupan iako je sučelje bilo mrtvo. Zahvaljujući tome mogao sam restartati na daljinu, odraditi downgrade i, prije svega, dalje čitati logove. Bez SSH-a to je bio jedini kanal u sustav. To je cijeli njegov doprinos i meni je dovoljan.
Herojstva tu nije bilo. Agent nije popravio SSD, dijagnozu mi nije skinuo s vrata, a ni od slijepe ulice me ne bi spasio. Spriječio je točno jednu stvar, a to je da posljednja preostala opcija bude „sjesti u auto”. Na tisuću dvjesto kilometara to vrijedi mnogo i svejedno ništa više od toga. Kako takav pristup izgleda kad ga se posloži kako treba, opisao sam detaljno u tekstu o daljinskom održavanju bez VPN-a i bez otvorenog porta.
Dvije stvari nosim u vlastitu praksu. Prvo, moj je pogled na jeftin hardver za pohranu od ovog slučaja osjetno manje prijateljski. Tko na SSD-u instalacije koja treba raditi godinama uštedi trideset eura, kupuje si traženje kvara koje košta višestruko. Kod integratora dolazi još i to da za ugrađeni dio odgovaraju dulje nego proizvođač. Drugo: sve što izmjestim u reflekse izvan poslužitelja radilo bi i tijekom ta dva dana. Pi je bio mrtav; svjetlo nije moralo biti.
I prava poanta
Daljinsko održavanje bez out-of-band pristupa ima svojstvo koje primijetiš tek u ozbiljnoj situaciji: svaki te restart košta dokaza. Ono što nije zapisano na disk nestaje s rebootom, a restartati je upravo ono što svi rade kad nešto zapne. Tri restarta često znače tri puta zametnut trag.
Baš je zato onaj prekinuti zapis u journalu vrijedio toliko. Bio je posljednji komad dokaznog materijala koji je preživio reboot. I nije iskazao baš ništa.
Samo je prestao.