Ted Ts'o az ext4 fájlrendszerrel kapcsolatos adatvesztés problémáról

Az Ubuntu Launchpad-on bukkant fel nemrég egy hibajegy, amelyben a felhasználó arra panaszkodik, hogy a kiadás előtt álló Ubuntu Jaunty-val és ext4 fájlrendszerre játszva adatvesztést szenvedett. A felhasználó egy áramkimaradás után azt vette észre, hogy az újraindított rendszerén a ktimetracker alkalmazás konfigurációs fájlja egy 0 byte hosszú fájlra cserélődött.

Arról nem szerzett tudomást, hogy más adat is sérült volna. Nem is tapasztalt ilyet, míg egy nap a BIOS beállításokkal addig játszott, hogy a rendszere összeomlott a desktop betöltése után. Újraindította a rendszert, majd azt tapasztalta, hogy egy rakás, alkalmazások (pl. Plasma, KDE core stuffok) által írt fájl 0 byte-os lett, illetve eltűnt néhány MySQL adatbázis.

A problémáról tudomást szerzett Ted Ts'o kernelhacker, az ext* fájlrendszerek egyik fő fejlesztője, karbantartója is:

"Nos, ismerem ezt a problémát és dolgozom a megoldáson, de mivel nem vagyok feliratkozva erre a bugra, nem volt tudomásom az itt folyó hatalmas diskurzusról egészen addig, amíg Nullack rám nem szólt és meg nem kért, hogy "vessél már egy pillantást a 317781-es bugra"."

Majd folytatta:

"A rövid válasz (a) igen, tudok róla, (b) van (részleges) megoldás, (c) még nincs a mainline [kernelben], és amennyire tudom, nincs az Ubuntu Kernel-ben [sem], de már várakozási sorban van a következő, 2.6.29 utáni beolvasztási ablaknál, és (d) ez sokkal inkább alkalmazás-tervezési probléma mint bármi más."

Az okok, részletek - és patch-ek - Ted kimerítő válaszában.

Hozzászólások

Más fájlrendszerek használata mellet sem árt egy szünetmentes tápegység...

Valaki magyarazza el nekem miert nem jo a (2) modszer. Hiszen a write es a close az a rename elott van. Tehat ha ordered modban hasznalom a filerendszert, akkor ennek is ebben a sorrendben kellene tortennie, nem? Ezert safe-nek kene lennie, es nem hozhat letre 0 byte-os fileokat.

Megmondom mi a problemam. TFH laptop modban hasznalom a notebookom, es 30 masodpercre noveltem a sync erteket. Es ezzel epp azt szeretnem elerni hogy tenyleg 30 masodpercenkent irjon a diszkre (nyilvanvaloan ha meg van a file cache-nek hely). Tisztaban vagyok vele, hogy az adataim csak 30 masodperc mulva lesznek biztonsagban. Valamit valtoztatok egy progi konfigjan, es meg mielott ki lenne irva a diszkre az uj konfig elhasal a gepem, reboot. Ilyenkor ha az alkalmazas a (2) modszert hasznalta, akkor a regi konfigomnak erintetlenul kellene maradnia. (Esetleg letezik egy "~/.kde/foo/bar/baz.new" 0 byte-os file.) Ilyenkor nincs semmi problema, tisztaban vagyok vele hogy az utolso 30 masodperc lehet nem kerult ki a diszkre, megnezem ujra az alkalmazas konfigot, es ha a regi, akkor ujra megvaltoztatom. De legalabb van mibol kiindulnom, mert megvan a regi. A legnagyobb bajom, hogy nem szeretnem ha minden alkalmazasom fsync-elne, hiszen epp azert allitottam be a 30 masodpercet.

En ugy ertelmezem, hogy (2) modszerben akkor lehet adatvesztes, amikor az uj filet nem lehet kiirni (mondjuk valami hardware problema miatt), de szerintem ezt akkor sem az alkalmazasnak kell lekezelnie fsync-el.

>> Tehat ha ordered modban hasznalom a filerendszert, akkor ennek is ebben a sorrendben kellene tortennie, nem? Ezert safe-nek kene lennie, es nem hozhat letre 0 byte-os fileokat.

nem a sorrend, hanem a mikor a kérdés: amint az eredeti hibajegyben láthatod egyszer áramkimaradás egyszer pedig system crash után tapasztalta a reportoló fiatalember a jelenséget (0 méretű kde 'konfigfájlok', mysql db-k)

> nem hozhat letre 0 byte-os fileokat.

Amikor létrehozok egy új fájlt, létre kell hozni neki egy könyvtárbejegyzést értelemszerűen 0 mérettel. Beleírok a fájlba mondjuk 300 karaktert. Ezután két sorrend lehetséges:

1: először a könyvtárbejegyzés frissül 300-as méretre, majd ezt követi a 300 bájt diszkre írása

2: először a 300 bájt kerül diszkre, ezt követi a könyvtárbejegyzés frissítése 300 bájtos hosszra.

A két lépés között lefagy a gép (vagy hw reset). A 2-es forgatókönyv szerint egy 0 hosszú fájl marad a diszken, az 1-es szerint meg egy 300 bájtos fájl, aminek valami zagyvaság a tartalma. Akkor inkább legyen 0 hosszú. És lett is. :-)

Aki jobban tudja, majd kijavít.

Csak a halál...
Én is így értettem amit Ts'o ír. Én nem értek az ext4-hez (sem), ő meg igen.
Tehát vagy félreértettem amit ír, vagy hülyeségeket ír.

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Valaki magyarazza el nekem miert nem jo a (2) modszer. Hiszen a write es a close az a rename elott van. Tehat ha ordered modban hasznalom a filerendszert, akkor ennek is ebben a sorrendben kellene tortennie, nem? Ezert safe-nek kene lennie, es nem hozhat letre 0 byte-os fileokat.

Mi az h. "ordered módban használod a fájlrendszert"? POSIX/SUSv3-ban hol látsz ilyet, hogy "fájlrendszer ordered módja"? Sehol. Ez egy ext3 specifikus opció. Épp ezen lamentál Tytso, hogy rászoktak a népek a (2)-re, ami ext3-mal (pl ordered mód mellett) tök faszán, biztonságosan működik, de nincs olyan része a sztenderdnek, amiből következne, hogy számítani lehet erre a biztonságos működésre. Az ext4 pedig -- a sztenderddel összeférő módon -- a teljesítmény javítása végett késlelteti a blokkok allokálását, ezért amikor megírja az app a dotfájl új verzióját, az nem garantált, hogy lemezre kerül rögvest. A könyvtárbejegyzések módosítása viszont nem jár blokallokálással, így az megtörténik rögtön (ill. legalábbis hamarabb), mint a blokkok allokálása, majd a stuff lemezre írása. Íme, a 0 bájtos fájl genezise. Tytso azt mondja, a sztenderd szerint csakis az fdatasync()/fsync() hívások révén garantálhatjuk, hogy az adat lemezre kerül.

Kíváncsi lennék amúgy, mi a véleményük erről a dilemmáról a Linux, ill. az ext* világán kívül tevékenykedő fájlrendszeres arcoknak.

"En ugy ertelmezem, hogy (2) modszerben akkor lehet adatvesztes, amikor az uj filet nem lehet kiirni (mondjuk valami hardware problema miatt), de szerintem ezt akkor sem az alkalmazasnak kell lekezelnie fsync-el."

meg amikor eppen akkor megy el az aram, amikor ugyan a progi mar letudta a dolgokat, de a cache-bol meg nem szinkronizalodott a diszk.

Azt írta, hogy az adatok valós diszkre kerülése később lesz, viszont a rename meg azonnal.

Ha a rename után van áramszünet vagy crash, akkor az adatok még nincsenek a lemezen: 0 hosszú fájl.

Ha adat írás után, rename előtt van fsync, akkor az adatok diszkre kerülnek, és ha jön is az áramszünet, akkor sincs gond.

G

"A rövid válasz (a) igen, tudok róla..."
...de eddig nem szóltam, hátha nem veszitek észre, haha

RSS-ből megnyitva a hírt: "oldal nem található" fogad.

With delayed allocation, we don't allocate a location on disk for the data block right away. Since there is no location on disk, there is no place to write the data on a commit; but it also means that there is no security problem. It also results in a massive performance improvements;

Nyilván én vagyok a hülye, de ez mitől alkalmazás-programozói probléma/hiba, hogy a hatékonyságot olyan eszközzel növelik driver szinten ami az adatbiztonságot veszélyezteti de nem kicsit?

Szoval azt akarod ezzel mondani, hogyha van egy fajlod, amit frissiteni akarsz, es mind a regi, mind az uj fajlod odavesz akkor az teljesen normalis?

Szerintem az adatvesztes elkerulese a legfontosabb egy fajlrendszernel, es nem a teljesitmeny.

---
Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

A default az szokott lenni, nem csak fájlrendszereknél, hogy a teljesítményért cserébe vállalnak kis esélyű veszélyeket, lásd pl. overcommit.
Ha valaki nagyobb biztonságot akar, állítsa be annak megfelelően a kernelt, fájlrendszert, hardvert, alkalmazásokat, na meg a saját szokásait. Azt is tudomásul kell venni, hogy ha helyben írsz felül egy fájlt, az eleve veszélyes dolog, nem csak fájlrendszer miatt.

Azt is tudomásul kell venni, hogy ha helyben írsz felül egy fájlt, az eleve veszélyes dolog, nem csak fájlrendszer miatt.

Nem azért osztotta a fejlesztőket Ted, mert effélét tettek volna (egyáltalán nem volt szó arról, hogy bárki ilyet tett volna). Az volt a mondanivalója, hogy az ennél biztonságosabb (és széles körben bevett) "írjuk az új adatot külön fájlba, majd rename(2) révén csapjuk felül vele a régit" eljárás sem elég tuti.

> es mind a regi, mind az uj fajlod odavesz akkor az teljesen normalis?

Igen, ha úgy van megírva akkor lehet teljesen normális, és ha máshogy van megírva akkor meg lehet hogy egyáltalán nem normális.

> az adatvesztes elkerulese a legfontosabb egy fajlrendszernel, es nem a teljesitmeny.

Egyedül csak a fájlrendszerrel nem lehet adatvesztést elkerülni. (Javítson ki aki jobban tudja.) Marad az, hogyha már úgyis úgy kell megírni a kódokat hogy az adatvesztés lehetősége benne van a tervben, akkor legalább legyen gyors.

Szerintem.

data=journal All data are committed into the journal prior to being
written into the main file system.

data=ordered (*) All data are forced directly out to the main file
system prior to its metadata being committed to the
journal.

data=writeback Data ordering is not preserved, data may be written
into the main file system after its metadata has been
committed to the journal.

Miert az ordered a default ? journal ez ellen ved ?

Amit nem lehet megirni assemblyben, azt nem lehet megirni.

Azt akarod mondani, hogy ha egy gép előtt nincs UPS, és az alkalmazások pongyolán vannak megírva, az teljesen normális?
Szerinted az 5..30 másodpercenkénti flush hivatott ezt a problémát megoldani?

Ebben az esetben pont az UPS meg a normálisan megírt programok és a stabil oprendszer lenne a megoldás. Meg ugye úgyis van backup.

POSIX fundamentally says that what happens if the system is not shutdown cleanly is undefined. If you want to force things to be stored on disk, you must use fsync() or fdatasync().

Szoval, ha garanciak kellenek neked, akkor fsync/fdatasync. Ha egyiket se hasznalod, akkor valoszinuleg nem igazan erdekel.

EDIT: kivancsi vagyok hany alkalmazas mukodne, ha az oprendszer egyaltalan nem sync-elne automatikusan, hanem csak amikor te erre explicit megkered.

Egy close utan sem lehetek nyugodt ?
szerk: RTFM
"
A successful close does not guarantee that the data has been successfully saved to disk, as the kernel defers writes. It is not common for a file system to flush the buffers
when the stream is closed. If you need to be sure that the data is physically stored use fsync(2). (It will depend on the disk hardware at this point.)
"
nem

Amit nem lehet megirni assemblyben, azt nem lehet megirni.

Hugom meg fog nyúzni, ha valami elveszik a gépén. Ő - illetve a gépe - volt a kísérleti nyúl az ext4-hez. :) Csak nem kell tudnia, hogy ezért is kapott új disztrót 2.6.28-as kernellel.

na'jsz ...

en asszem megvarom az opensuse 11.2 es majd akkor allok at, addig az ilyen dolgok tisztazodnak, talan javitanak par programon, talan lesz workaround az ext4 driverbe.

btw: nem is tudtam hogy formazas nelkul lehet ext3 -rol ext4 -re konvertalni, azt hittem csak kompatibilitas modba viszi majd: http://linuxpoison.blogspot.com/2009/01/ext4-support-on-opensuse-111.ht…

Mióta vannak tranzakció logok a fájlrendszereken nem az lenne az üdvözítő megoldás, ha lenne hozzá API, hogy tranzakció start és tranzakció zárás?

Akkor lehetne úgy is fájlt írni, hogy:
1. tranzakció kezdete
2. trunc
3. Írás
4. tranzakció zárása
És akkor az azt jelentené, hogy vagy a régi fájl ott van vagy az új ott van. És lemezre írási idő eltelte után biztos, hogy az új van ott. Mégse kellene fsync-cel az alkalmazásnak a lemezre várni.

Mondhatjuk hogy tranzakciókezelés fájlrendszerre túlzás, de a 3. megoldásnál még ez is egyszerűbb.

Néha az az érzésem, hogy a kernelhackerek szemszögéből a userspace csak egy felesleges nyűg, amit jó lenne teljesen megszüntetni :).

Kovezzenek meg a UNIX/POSIX huszarok, de csak azert kovetni egy specifikaciot, mert az POSIX szabvany, es nem gondolkodni kozbe szerintem nem a legjobb fejlesztesi modell. Fel kellene talan ismerni, mi hibas es mi a kovetendo.

Az mar csak hab a tortan, hogy a diszkkezeles messze nem a userspace alkalmazas feladata _semmilyen szinten_, hanem kizarolagosan az alatta futo rendszere (kernele). Nem hiszem el, hogy ezt nem kepes egy magat programozonak mondo emberke/csapat elkepzelni. Mi lesz a kovetkezo? A SCSI/ATA parancsok kiadasa is az alkalmazas feladata lesz?
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Ezzel nekem csak egy problémám van:
Mit csináljak, ha balga módon nem C-ben fejlesztek, hanem magasabb szintű programnyelven.

Ezekben maximum flush van, az viszont nem elég...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Én nem vagyok programozó, de az nem lehetséges, hogy legyen mondjuk egy safe_replace függvény, ami mindezt rendesen megcsinálja? Csak mert ugye a a szabad szoftver érájában boldog boldogtalan elkezd hekkelni, úgyhogy nem várható el, hogy mindenki UNIX expert legyen. Akkor meg lehetne leszűkíteni a kört az „elitre”, akik a programnyelveket írják, olyan fv-ekkel, amikkel a hülye is tud biztonságos/nem adatvesztő kódot írni. Vagy tévedek.