A késleltetett allokáció és a nulla hosszúságú fájl probléma

Ted Ts'o korábban már jelezte, hogy tud az ext4 fájlrendszerrel kapcsolatos "0 hosszúságú fájl" problémáról és le is írta véleményén a Launchpad-on. Most blogjában, eként összegezve:

"Jelenleg azt javaslom azoknak az Ubuntu gamer-eknek, akinek a rendszere állandóan összeomlik és ext4-et akarnak használni, hogy használják a "nodelalloc" mount opciót. Nem mértem, hogy milyen teljesítmény hátránya lesz ennek a működési módnak, de a teljesítmény jobb lesz mint ext3 esetén és legalább így nem kell aggódniuk, hogy a késleltetett allokáció eredményeként elvesznek fájlok. Hosszútávon, az alkalmazásokat írók azok, akiket aggaszthat, hogy egy nem szabályos leállás esetén fájlvesztés léphet fel, [nekik] tényleg az fsync-et kellene használniuk. A modern fájlrendszerek mindegyike a késleltetett allokáció felé halad a benne rejlő előnyök miatt és mindegy, hogy szerinted a jövő a ZFS, a btrfs, az XFS vagy az ext4 -- ezen fájlrendszerek mindegyike használja a késleltetett allokációt."

A teljes írás elolvasható itt.

Hozzászólások

ez most olyan, mintha nem bug lenne, hanem feature. legalábbis nagyon megmagyarázza hogy jó ez így.
csak a hírt olvastam el, nem jártam utána, szóval csak a fent említettekből szűrtem le a véleményem.

Akkor a disztrók majd csinálnak valamit, pl ha ext4-et választasz, az fstabba beírják a kellő mount opciót, vagy valami. Akinek egyébként egy otthoni gépen / laptopon / irodai gépen feltétlenül ext4 kell, annak súlyos szociális problémái vannak. Szerver meg "nem fagy le normál esetben".

********************
http://holo-media.hu
Debian GNU/Linux 5.0 "Lenny" i386

Igen lehetne, de aki úgy van, hogy fájlrendszerek közötti választáson gondolkozik, vegye a fáradságot, hogy ezt a mount opciót is beletegye az fstab -ba. Egyébként van olyan disztró aminek a stabil kiadása ext4 -et felkínál rootfs -nek vagy bárminek? Tudtommal nincs. Innentől kezdve "hack" az egész, legalábbis jelenleg.

********************
http://holo-media.hu
Debian GNU/Linux 5.0 "Lenny" i386

+1
Arch 2009.2.
Mikor felraktam a tesóm gépére, akarattal ext4-re formáztam. Szeretek kisérletezni. (Más gépén.) Semmi bajom nincs vele. (Főleg mert nem én használom.) Desktop.
:)

Lehetséges, hogy az ext4-es partíción nyugvó Arch a fájlrendszer miatt bootol ilyen veszettül gyorsan?

az adatnaplozo FS -ek sem garantaljak az adatveszetlenseget
a metaadatjournaling rendszerek a metaadat konzisztenciajat biztositjak minden esetben (tehat a filesystem maga nem omlik ossze) es programozoi feluletet adnak az alkalmazasnak, hogy az alkalmazas sajat adataival is ugyanezt elerhesse (fdsync,fsync)
az ext3 fele ordered data mode es a data journaling mode csak nagyon-nagyon keveset ad hozza a metaadat naplozashoz, megpedig azt, hogy a file tartalma minden esetben nem a diszken regebben levo szemet, hanem, amit a program kiirt
De nem garantaljak azt, hogy amit a program utoljara irt ki

Szoval csak konzisztenciat garantalnak, nem minden adat megletet.

Pl. ha ext3 -mal adatvesztes nelkuliseget szeretnel elerni, akkor data_ordered, sync modban kell mountolnod. Ezzel a teljesitmenye valahol tizedere csokken.

Probald ki a kovetkezot (metaadat journaling teszt)


char tmp[50];int i;
for(i=0; 1; i++){
sprintf(tmp,"tmp%d.tmp",i);
close(creat(tmp,0));
fprintf(stderr,"%d ",i);
}

ssh-z be, inditsd el a progit, menj oda a gephez, huzd ki a tapkabelt, bootold vissza, nezd meg, hogy mi van a directoryban ahoz kepest, amit az ssh ablakban latsz. Par file altalaban hianyzik, kiveve, ha sync modban van nyitva az fs.
Kiprobalhatod ezt is:

char tmp[50];int i, fh;
for(i=0; 1; i++){
sprintf(tmp,"tmp%d.tmp",i);
fsync(fh=creat(tmp,0));
close(fh);
fprintf(stderr,"%d ",i);
}

elvileg :-) eredmenyeben (es lassusagaban) az elozo pelda sync mountolt futtatasat adja vissza async (default) mountolassal is.

Most lepjunk a halado szintre, es nezzuk meg, hogy mi tortenik, ha a biztonsag novelese erdekeben raid5 -ot hasznalsz vagy esetleg lvm -en van az fs. Ezek a cuccok eldobjak a barriert, a journal konzisztenciajat nem garantalja semmi algoritmus, az fsync/fdsync helyes eredmenyu lefutasat sem garantalja semmi kod, teljes filesystem osszerogyas (na jo, az fsck hibat talal) bekovetkezhet (fog bekovetkezni, ha eleg sokszor probalod).

Ez világos, csak az nem, hogy most általánosságban, vagy konkrét dolgokról beszélünk.
Ha minden fájlrendszert érintő módosítást naplózol garantált, hogy a módosítást végző művelet visszatérésekor biztonságban van az adatod (feltéve persze, hogy a hardver nem veri át a szoftvert).

Hogy ez lassú? Oh well. A szinkron írásnál azért lehet gyorsabb, hiszen a naplót szekvenciálisan (esetleg egy erre a célra kiképzett eszközre) írhatod.
(végsősoron mintha a MySQL-ben is default autocommit lenne, azaz az ottani adatbázis-analógia szerint nem csak commitkor (fsync és társai), hanem minden egyes művelet után van logírás)

A végén megint a Linuxról írsz, pedig ha körbenézel láthatod, hogy máshol (biztos a Linuxban is, a btrfs-nek tudnia kell ezt!) ezt már megoldották...

Vegul is ezert irtam, hiaba nez ki flamenek:
fájlrendszert érintő módosítást naplózol garantált, hogy a módosítást végző művelet visszatérésekor biztonságban van az adatod
ez a legnagyobb teveszvme a journaled filesystemekkel kapcsolatban. programozo-user-rendszergazda mind ezt hiszi, de nem. A journal nem azt biztositja, hogy az adataid megvannak, hanem azt, hogy a filesystem konzisztens. A metaadat-only journal is. A data journal is csak a konzisztenciat biztositja. Az adataid megletet a {f,fd,}sync biztositja, nem a journal.

megint a Linuxról írsz

[az sw raidet] nem igazan oldottak meg. A kovetkezoek vannak:
- (linux modell) az sw raid/lvm dobja a barriert, az elemi diszkeken a tranzakciokat rendezi. Ettol gyors, es veletlen aramszunet eseten korrumapalhat
- (vms modell) barrier fogalom nincs, az irasi muvelet nem rendezheto, az elemi irasi egyseg egy blokk. Ettol hasznalhatatlanul lassu, de veletlen aramszunet eseten nincs korrumpalas
- (hw storage modell) az irasi muveletek rendezese, es cachelese nvramban (aksival taplalt memoria) tortenik, igy veletlen aramszunet eseten a meg kiirt (de visszajelzett) adatok is megmaradnak, nem korrumpal, gyors (nem olcso)
- (raid+fs single layer modell: zfs a sun-tol, wafl a netapp-tol) a tobbdiszkes kezeles soran irasi journalt vezet egyetlen devicen, a journal orzi a barriert es lehetoseget ad a irasrendezesre. A journal device sebessege limitalja az egesz sebesseget. Emiatt adnak zfs ala villamgyors ssd-t, a netapp meg mindenutt nvramot alkalmaz wafl journalnak.
Ez annyiban kulonobozik a "hw storage modell" -tol, hogy teljes filesystem, nem pedig blockdevice, igy elvileg a journal csak a barrier megtartasahoz szukseges dolgokhoz kell. (konkretan a wafl nvram a teljes irasi mennyiseget tarolja, tekintheto ez adat+metaadat journalnak, a zfs internalrol meg fogalmam sincs)

gyors, stabil, specialis hw nelkuli megoldas, hm, nincs.
A vms modellnel gyorsabb, a linux modellnel lassabb sw raid lehetne azert, lehet, hogy van is: a virtual device (array/lvm) irasi sora a barrier hatasara megall, es csak akkor folytatja a fizikai diszkekre az irasi sor szetdobalasat, amikor a fizikai diszkeken levo irasi sorok mind kiurultek (az osszes). Sajnos a linux device modellben nincs (vagy nem tudom hogy van) ilyen lehetoseg, az egyeb oprendszerek sw raid/lvm megoldasairol ilyen szinten nem tudok semmit.

Az "adatvesztés" jelen esetben annyit jelent, hogy csak a nem kiírt adatok vesznek el, ha jól értem.

Vagy összetudja úgy kuszálni a file-rendszer a dolgokat, hogy régi adat is elveszhet?

Az előző annyira nem gáz, tekintve, hogy milyen ritkán van nem szabályos leállás, a második már aggasztóbb.

Hogyha a bugos alkalmazás már meglévő file-t ír felül (O_TRUNC), akkor nem szabályos leálláskor előfordulhat, hogy a régi adat már, az új pedig még nincs meg. Ez szerintem inkább az első kategória, mint a második, mert a file rendszer nem kuszálódik össze, és nem random file-ok tartalma veszik el, hanem csak azoké, amik tartalma amúgy is elvesztésre volt kárhoztatva.

Az adatvesztés, amiről most szó van azt jelenti, hogy ha egy file-t újraírsz (azaz a régi tartalmát eltünteted és új tartalommal helyettesíted), akkor előfordulhat, hogy se a régi, se az új tartalom nem lesz meg egy összeomlás után. Tehát maga a file rendszer nem lesz korrupt, csak az ily módon újraírt file-ok 0 byte-osak lesznek. Ehelyett azt várná el az ember, hogy vagy a régi, vagy az új változat azért meglegyen.

Biztonságos annyira, mint ext3 esetén volt (amire válaszoltam).

Egyébként maga a rename biztonságos, mert atomi művelet.

Ha az átnevezni kívánt fájl még nincs a lemezre valójában kiírva, a rename akkor is átnevezi biztonsággal. Csak persze a fájl üres marad ettől.

A rename biztonságos. Csak a rename nem fog semmit megborítani, nem okoz üres fájlokat.
A delayed allocation nem biztonságos.

Az, hogy valaki delayed allocation miatt üres fájllal biztonságosan felülcsap egy másikat, az más kérdés.

Most mondhatnám, hogy olvasd el a cikket, de gondolom elolvastad. Csak félreértetted amit írtam. Ugye?

kicsit OFF:

"Egyébként maga a rename biztonságos, mert atomi művelet."

Tényleg atomic és biztonságos, csak nem minden esetben működik.
Pl. különböző mount pointokon keresztül, hiába ugyanaz a fájlrendszer. Ez gond lehet, ha pl. a /tmp -ben hozol létre tempfile-t hogy a /etc -ben módosíts.

ERRORS
...
EXDEV oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points, but rename() does not work across different mount points, even if the same filesystem is mounted on both.)

__________________________________________
még nincsen kész, de már majdnem elkezdtem

Én, ha fejlesztő lennék, nem szeretnék mindenhova fsync-et tenni. Ugye teljesítmény. Laptopban felpörgő hdd, stb.

Viszont akkor ezentúl nem felülírnám a régi fájlt, hanem átnevezném fájl~ névre (ez ugye atomi művelet), az újat meg létrehoznám fájl néven.

Ha közben baj van, az új elvész, a régi megmarad.

G

> Ha közben baj van, az új elvész, a régi megmarad.

A fejlesztőnek meg emlékeznie kell, hogy nehogy véletlenül lementsen egy default konfigot abban az esetben, amikor üres (0 hosszú) a konfig fájl. Mert akkor a 0 hosszú konfigból készül egy backup, ami miatt elveszik a "régi".

Miért, a videoszerkesztő konfigurációs fájlja olyan speciális?

Vagy ha az adatfájlra gondoltál, akkor másról beszélünk. Én (és azt hiszem, a többiek is) konfigurációs fájlokról. Kis méretű szöveges cuccokról.

Mondjuk videoszerkesztésnél nem tudom, hogy megy, de azért az nem tűnik jó megközelítésnek, hogy minden lépésnél a teljes, sok gigabájtnyi anyagot újra kiírjuk...

G

"Mondjuk videoszerkesztésnél nem tudom, hogy megy, de azért az nem tűnik jó megközelítésnek, hogy minden lépésnél a teljes, sok gigabájtnyi anyagot újra kiírjuk..."

Szerintem pont erre gondol: csúnyán lassú lenne, ha a videószerkesztő "renderelésnél" minden egyes írás után fsync() -et kéne hogy hivogasson...

Nem értem ezt a videoszerkesztő dolgot. Ha renderelésről/konvertálásról van szó, akkor az egy megismételhető művelet. Összeomlás után újra lehet kezdeni, nincs adatvesztés. Az ellen pedig nem lehet tenni semmit, hogy ha kikapcsol a gép egy 5 GB-os file írása közben, akkor mondjuk bekapcsolás után egy 3 GB-os file fogad, mert épp ott kapcsolt ki. A filerendszer nem adatbázis.

fsync nélkül is baromi lassú kiírni mondjuk 25 gigabájtot, ami kb. egy másfél órás DV film mérete.

Nem tudom, a videoszerkesztők hogy csinálják, én bizonyára addig nem írnék semmit (csak konfigurációs fájlokat, adott projektet leíró xml-t), amig csak szerkesztgetés megy, és a végén, amikor az ember rábök a generate gombra, akkor kezdeném újrakódolni és kiírni.

A konfigurációs fájlokat jó lenne megőrizni (fsync), a nagy fájlt meg felesleges syncelni.

Ezért nem értem, mire gondolt ő, hiszen a konfigurációs fájlokról beszéltünk eddig.

G

forditva,

az egyben hatalmas adatmenyiseg (a szobajoheto cache rendszerek sokszorosa) szekvencialis kiirasan nem lassit az fdsync/fsync/syncmount opcio, hiszen ugy is ki kell irni, es ugy sincs mas dolga a gepnek. Ket parhuzamos hatalmas adatmennyiseg kiirasan mar jocskan gyorsithat ;) az egyikbol olvas - masikba ir jellegu programoknal szinte sokat gyorsit a buffereles, ha a forras es a cel azonos diszken/diszkeken van.

Nem tudom, a videoszerkesztők hogy csinálják, én bizonyára addig nem írnék semmit (csak konfigurációs fájlokat, adott projektet leíró xml-t), amig csak szerkesztgetés megy, és a végén, amikor az ember rábök a generate gombra, akkor kezdeném újrakódolni és kiírni.

Ez így történik. Ezenkívül a szerkesztést egy preview állományon végzed, ami kezelhetően kicsi. A renderelés egy hosszabb folyamat, akkor áll elő a kész mű. Egyébként pont erre gondoltam egy másik hozzászólásomban, amikor azt állítottam, van elfogadható adatvesztés. Persze nem öröm, amikor egy párórás renderelés megy veszendőbe, de ettől még reprodukálható marad.

Ave, Saabi.

Ha konfig fájlok mentéséhez teljesítmény kell, akkor szerintem már régen rossz.

Ha meg épp egy nagy csomó adatot állít elő, akkor meg mindenképp illik időnként egy sync-et nyomni neki, hogy biztos kinn legyen egy jókora része diszken stb.

Nem véletlenül ír ilyeneket Ted, hogy meg kellene tanulni programozni.

Érdekes. Szerintem az ext4-ben van más bug is.. a Jaunty (Alpha 6) a telepítés után nagyjából 2GB-ot foglalt a 4GB-jából. Most ott tartok, hogy van 40MB helyem és hal le szépen lassan minden, pedig semmi adat nincs rajta, mivel csak tesztelek ezen a rendszeren..

aptitude clean is volt már, a Janitor-al leszedtem pár régi csomagot, de csak ideiglenes megoldás, mert olyan hamar teli lesz a lemez mintha folyamatosan szívná el valami a helyemet, vagy a hely felszabadítás nem működne jól, esetleg volt 1-2 kissebb áramszünet mostanság azt tett be neki..

Megyek ráengedek egy fsck-t, hátha rendbetesz valamit...

Theo a következőket mondja:
- Ha nem használsz f*sync-et, akkor nincs mód arra, hogy teljes biztonsággal lecseréld egy file tartalmát delayed allocation használatával.
- A delayed allocation azért jó, mert jelentősen növeli a teljesítményt és csökkenti az energiafelhasználást.
- Ha fsync-et használsz, akkor kiütöd a delayed allocation-t, elveszted minden előnyét.
- Ext3 esetén az f*sync botrányosan lassú.

Tehát, ha egy userspace alkalmazás fejlesztője nem használ f*sync-et, akkor ext4 delayed allocation fájlrendszeren, és ZFS, btrfs, XFS esetében is adatok veszhetnek el áramkimaradás vagy összeomlás esetén.

Ha pedig használ f*sync-et, akkor értelmetlenné válik a delayed allocation, rossz lesz a teljesítmény, állandóan felpörög a merevlemez, és ha elvetemült módon ext3-on indítják az alkalmazást, akkor akár percekre megakadhat, ha közben egy nagy file-t is másol a felhasználó.

Nekem egyik választási lehetőség sem tetszik. Ha az alkalmazások elkezdik nyomatni az fsync-et, akkor a teljesítmény érdekében egy üres függvénnyel fogják implementálni, ahogy teszi az OS X. És senkinek nem lehet egy szava sem, ugyanis a POSIX szabvány lehetővé teszi ezt. Theo is mindig a POSIX-ra hivatkozik, hogy a műveleteknek nem kell olyan sorrendben végrehajtódniuk, mint ahogy a programban szerepelnek.

Szóval szerintem oda lyukadtunk ki, hogy a POSIX szabvánnyal azt az egyszerű use case-t, hogy szeretném egy notepad kaliberű programmal egy text file tartalmát módosítani, nem lehet egyszerre biztonságosan és hatékonyan elvégezni. Vagy biztonságosan csinálom rossz teljesítménnyel, vagy gyorsan és utána imádkozva.

Feltételezem nem arról szól az fsync használatáról szóló javaslat, hogy mindig és állandóan használd, mert akkor minek van buffercache-ed egyáltalán?
Viszont vannak olyan helyzetek, amikor fontosabb az adatok garantált disk-re pakolása, mint a teljesítmény. A konfigurációs állományok történetesen ilyenek. Kisméretűek, ritkán változnak, hiányuk viszont működésképtelenséget eredményez.
Más típusú adatfeldolgozásnál fontosabb a teljesítmény, viszont elfogadható a rendszer összeomlásának amúgy se túl nagy kockázata. Gondolok itt elsősorban olyan adatfeldolgozásra, mely megismételhető ha a forrásadatok rendelkezésre állnak.

Ave, Saabi.

Valóban vannak olyan használati esetek (use case-ek), melyeknél nem probléma az adatvesztés. Ilyen pl. a programfordítás vagy az audio/video konvertálás. Ezeknél nincs is gond.
Amit mondani akarok, hogy sok esetben az adatvesztésnek a csekély valószínűsége sem elfogadható. És azért jó lenne, ha lenne erre az esetre is egy tuti megoldás, vagy ajánlás. Ilyenek a config file-ok, de egy MyISAM adatbázistábla is. Márpedig jelenleg mind a KDE, mind a GNOME úgy viselkedik, hogy ha arrébb húzol egy ablakot, vagy átállítasz egy opciót, rögtön írja ki a megváltozott konfigurációt. Praktikusan állandóan dolgoztatja a merevlemezt, az nem tud pihenni. Erre nem kellő megoldás, ha minden konfigurációt adatbázisban tárolnának, egyrészt nehezen adminisztrálhatóvá válna, másrészt az adatbáziskezelők is állandóan fsync-et hívogatnak.

Van még egy nagy különbség. Az ext3 ordered módban az fsync az összes addigi, még nem sync-elt fájlműveletre vonatkozott, ezért volt nagyon lassú. És ezért szoktak le az alkalamzásfejlesztők a használatáról.

Az ext4-nél csak az aktuális fájlra van hatással, ezért lényegesen kevésbé lassít.
---
Linux is bad juju.

> Ha fsync-et használsz, akkor kiütöd a delayed allocation-t, elveszted minden előnyét.

Nem, arra a "nodelalloc" mount opció való.

> nem használ f*sync-et [...] adatok veszhetnek el áramkimaradás vagy összeomlás esetén.

Akkor is veszhetnek el adatok, ha használja.

> Ha pedig használ f*sync-et, akkor értelmetlenné válik a delayed allocation,

Ha minden program, minden write() után fsync()-elne, akkor ...

> nem lehet egyszerre biztonságosan és hatékonyan elvégezni.

Nincs biztonság, és soha nem is volt, csak rövidebb (hosszabb) időtartamig tartó sérülékenység van.

Szerintem.

Akkor is veszhetnek el adatok, ha használja.
Nincs biztonság, és soha nem is volt, csak rövidebb (hosszabb) időtartamig tartó sérülékenység van.

A naplózó fájlrendszerek csodája, hogy a rename atomi művelet. Vagyis a régi és az új tartalom közül az egyik garantáltan meglesz, egyáltalán nincs sérülékenység. Ezt már az ext3 is tudta, ez volt a nagy-nagy előnye az ext2-höz képest. Az ext4 is tudja ezt természetesen, de ott csak az fsync garantálja, hogy a write előbb hajtódjon végre, mint a rename. Szemben az ext3 data=ordered módjával, ahol ha a kódban előbb volt a write, akkor előbb is hajtódott végre.

Ha backupba ír a program, aztán átnevez, akkor az ext3 data=ordered módban teljes biztonságot ad az ellen, hogy a file elvesszen. Bármikor is essen ki az áram. És ehhez nem kell f*sync. Más a helyzet ext4 esetén, ott kb. 2 perces ablak lesz, hogy ha akkor történik szabálytalan leállás, elvesszen az adat.

- Ha nem használsz f*sync-et, akkor nincs mód arra, hogy teljes biztonsággal lecseréld egy file tartalmát delayed allocation használatával.

Attól függ. Ha nem felülírsz, hanem másik fájlba írsz, majd rename-elsz, akkor hiba esetén a régi fájltartalom még biztosan meglesz, akkor is, ha nem fsync-elsz.

- Ha fsync-et használsz, akkor kiütöd a delayed allocation-t, elveszted minden előnyét.
Ha feltétlen biztos akarsz lenni abban, hogy az _új_ tartalma legyen meg a fájlnak, akkor igen. Ha elég annyi is, hogy vagy az új, vagy rossz pillanatban történt (tehát ritka) hiba esetén legalább a régi, akkor nem kell az fsync.
---
Linux is bad juju.

Miért zavarna bele? Ebben a pillanatban még a hozzá sem értünk a régi fájlhoz, olvasásra nyitottuk csak meg. Az utolsó lépés az egész folyamatban, hogy átnevezzük az újat a régi nevére. Arra kell csak valami barrier, hogy az átnevezés és a régi fájl deallokálása ne tudjon a kernelben elé kerülni az új fájl tartalom kiírásának. Ha jól értem tytso szavait, akkor elvileg ez sem garantált a POSIX API leírás szerint, de erre az esetre konkrétan mégis figyelnek a legtöbb delayed transactiont használó fájlrendszernél, míg az in-place rewrite-ra nem.
---
Linux is bad juju.

Jó hát most figyelj, erre mit tudok mondani... Az fsync és semmi sem véd akkor, ha a diszk maga döntheti el, hogy mit ír ki és mikor. Pláne, ha még hazudik is a flush művelet befejeződéséről, mint ahogy a desktop drive-ok egy jó része teszi. De ez ellen semmiféle API-val vagy kernel szemantikával nem tudsz tenni. Nem teljesen véletlen, hogy a diszk write cache-t szerver környezetben általában még defaultból sincs engedélyezve, sőt az SSD-k többsége meg egyáltalán nem is csinál write cache-inget (ezért olyan lassúak).
---
Linux is bad juju.

> De ez ellen semmiféle API-val vagy kernel szemantikával nem tudsz tenni.

Szerintem se. Együtt kell élni ezekkel a jelenségekkel. Például ha egy program tudja detektálni, hogy az aktuális prg.conf fájl hibás (0 hosszú, vagy hiányzik a vége), akkor megpróbálhatja használni a prg.conf.bak -ot.

Ezesetben ajánlatos egy olyan technológiát használni a disk-ek felett, amit RAID-nek hívnak.

Lássuk be, adatvesztés lehetősége egy nem megfelelőlen umountolt filerendszeren azért nem egy újkeletű dolog. Léteznek is megoldások ennek elkerülésére, pl. UPS, RAID. Csak ezeket használni is kellene...

Ave, Saabi.

Attól függ. Ha nem felülírsz, hanem másik fájlba írsz, majd rename-elsz, akkor hiba esetén a régi fájltartalom még biztosan meglesz, akkor is, ha nem fsync-elsz.

Nem. Ezt a POSIX nem garantálja, és az új filerendszerek sem. Ez az egész "bug"-nak a lényege. Ezt csak az ext3 data=ordered módja garantálta, ami csak egy kivételes eset. Persze az elterjedtsége miatt sokan alapoznak erre a viselkedésre.


>> - Ha nem használsz f*sync-et, akkor nincs mód arra, hogy teljes biztonsággal
>> lecseréld egy file tartalmát delayed allocation használatával.
>
> Attól függ. Ha nem felülírsz, hanem másik fájlba írsz, majd rename-elsz, akkor
> hiba esetén a régi fájltartalom még biztosan meglesz, akkor is, ha nem fsync-elsz.

Bah. Kéretik olvasni, mielőtt száj kinyílik. Na de tényleg.

https://bugs.launchpad.net/ubuntu/jaunty/+source/linux/+bug/317781/comm…
[Amely postról konkrétan volt szó itt a HUP-on is ugyi.]

Épp arról szól az egész problémázás, hogy a bevett "másik fájlba írsz + rename révén felülcsapod vele a régit" pattern nem elég tuti a delalloc miatt, ha nincs fsyncelés.

volt olvasva, de kérdezem én: tényleg sikerült ezt a hibát rename-eléssel is reprodukálni? A fő offenderek alapvetően az O_TRUNC-ot használó alkalmazások voltak. Tény, hogy nem formálisan korrekt még a rename-es sem, de elméletileg még az ext3 ordered + 5sec commit sem az (pl ha a diszk borítja fel a sorrendezést) mégsem fordult elő ez a hiba ott.

UPDATE: egyébként most jöttem rá, hogy hol beszélünk el egymás mellett.

Én erre az esetre gondolok (kissé pszeudokódban):

fold = open("a", O_READ);
fnew = open("a.new", O_CREAT);
read(fold, &valami);
modify(&valami);
write(fnew, &valami);
close(fold);
close(fnew);
rename("a", "~a");
rename("a.new", "a");

Szerintem egyetlen esetben tudja elveszteni a fájl mind régi mind pedig új tartalmát: ha nemcsak, hogy a rename-ek megelőzik a write-ot, de még fel is cserélődik a két rename. Na ez utóbbit már kétlem, hogy a POSIX megengedné, mert ennek már erősen szemantikát befolyásoló hatása van. Ezt már tényleg csak a diszk vezérlő átsorrendezése idézheti elő, de akkor a naplózást is valami nagyon bizánci módon kell kijátszania (a második rename-et ki kell írnia a naplóba, sőt a commitot is, miközben a naplóba az első rename megkezdése sem került még bele), aminek nem sok esélyt adok.

Igen, olyan állapotot hagyhat maga után, hogy az "a" fájl 0 byte-os, de a korábbi tartalma még akkor is megvan a "~a"-ban.
---
Linux is bad juju.

> Szerintem egyetlen esetben tudja elveszteni a fájl mind régi mind pedig új tartalmát:

Ha a két rename() között fagy le, úgy hogy az első teljesen végrehajtódott, a második pedig egyáltalán nem:


                      // van "a" nevu fajl
rename("a", "~a");
                      // nincs "a" nevű fájl
rename("a.new", "a");
                      // van "a" nevu fajl

Ezért javasoltam az első rename() helyett link()-et.

Van benne valami, a link jobb, egyszerűbb a cleanup utána.

Mindenesetre a lényeg, hogy azt akartam az elejétől fogva mondani, hogy ha nem nagy baj, ha csak a régi tartalma van meg egy fájlnak (márpedig szerintem van sok ilyen eset), akkor lehet olyan megoldást találni, ami nem fsync-el. Igen, sajnos kell utána külön cleanup, mert nem biztos, hogy a rendes nevén találjuk meg.
---
Linux is bad juju.

Szerintem egyetlen esetben tudja elveszteni a fájl mind régi mind pedig új tartalmát: ha nemcsak, hogy a rename-ek megelőzik a write-ot, de még fel is cserélődik a két rename.

Ez már egész jó, de ahhoz, hogy ne lehessen baj, gondoskodni kell arról, hogy az adat lemezre írási intervallumán belül kétszer ne hívódhasson meg ez a kódrészlet. És persze arról, hogy ha "a" érvénytelen, akkor próbálkozzon "~a"-val olvasásnál. És máris egész tekintélyes kód kerekedik egy amúgy egyszerű műveletre.

Hm, ez érdekes felvetés, úgy tűnik valóban, h ilyenkor az adat meglesz valahol. Csakhogy:

  • Mi van akkor, ha az app nem szeretne backup fájlokat hagyni a dotfájlokból?
  • Ha az adott dotfájl kulcsfontosságú az app normális indulásához, akkor azért elég nagy baj, ha a rendes nevén nincs meg az adat -- mégcsak nem is az van, hogy az r=1 userek széttárják a kezüket, hanem egyáltalán, aki nem vágja, hogy mit hol tárol a program, az nemigen fogja tudni, pontosan melyik dotfájlt kéne helyreállítani a backupjából.
  • A te módszered is megverhető :) (ha az első rename helyett link van, akkor is).
    Mégpedig akkor, ha kitekintesz egy ilyen kvázi-tranzakció keretei közül. Mert ugye lehet, hogy gyakran frissíti az app a fájlt (hisz épp ez az, ami miatt egyáltalán baj van: ha ritkán frissítené, nem fájna az fsyncelés). Ha meg két ilyen kört nyomsz, akkor a 0-ik (diszken levő) verziót helyettesíti az 1-es, még ki nem írt verzió, 0-ik megy backupba, aztán a 2-es (szintén ki nem írt) helyettesíti az 1-est, az 1-es megy backupba, a 0-dik pedig eltűnik. Van egy 0 bájtos dotfájlod 0 bájtos backup verzióval :)

Igen, ezt már Archimonde is kiszúrta. Le kéne porolnom a Petri-hálós ismereteimet, hogy ne nézzek be ilyet. :) Vagy inkább a fejlesztőknek és különösen az API tervezőknek kéne a figyelmébe ajánlani a Petri-hálókat, hogy ők ne nézzenek be ilyeneket...

A kérdés akkor viszont megint nyitott: hogyan lehetséges olcsón fájlokat írni, ha nem nagy probléma az, hogy esetleg egy elszállás után nem a legutolsó változat van meg?

Az fsync, fdatasync párossal az a baj, hogy - mint nevük is mutatja - szinkron műveletek, híváskor azonnal végrehajtódnak és csak akkor térnek vissza, ha készen vannak. Igazából ide nem kell ez, lehetne őket jócskán késleltetni is. Az egyetlen szerepe, hogy egy barriert rakjon a write és a rename közé, hogy a sorrendjük ne cserélődhessen meg. Erre tényleg nincs olcsóbb művelet?

Külön szál indítással, saját várakozási sorral, saját fsync időzítővel tudnám csak elképzeli, hogy ezt meg lehessen oldani, de ez megintcsak túl bonyolult és erőforrászabáló.
---
Linux is bad juju.

Na még egy alap kérdés.

Akkor az ext4 jelen állapotában laptopra kíváló? Áramszünet miatti hirtelen leállás esélye gyakorlatilag szinte 0, ellenben a késleltetett írásnak köszönhetően ritkábban és kevesebbet nyúl a winchesterhez így akkuidő takarítható meg?

Esetleg rosszul értelmezem a dolgokat, vagy nincs túl nagy különbség és nem számít?

Vagy az akku töltésjelzője meghülyül vagy csak simán pontatlan (ahogy öregedik az akku előbb-utóbb ez garantáltan bekövetkezik a cellák eltérő mértékű elhasználódása miatt) és "meglepő" pillanatban merül ki. Tapasztalataim szerint notin sokkal gyakoribb a nem rendes shutdown, mint desktopon.
---
Linux is bad juju.

Én ezt az egész problémát nem igazán értem.
Segítsetek mit gondolok rosszul.
Az én szememben az nem fordulhat elő, hogy egy ilyen "hibás" mentésnél (csonkolásra nyitás, új adat kiír, lezár) se a régi, se az új tartalom ne legyen meg!
A naplózó fájlrendszer lényege abban kellene legyen, hogy ennek a helyes és gyors menetét biztosítsa.
A naplózó fájl rendszer használhat késleltetett allokációt, tetszőleges sorrendben írhatja ki az adatokat, ahogy neki tetszik, DE!, amíg nem küld a program flush() vagy close() üzenetet, addig ne csináljon semmi visszavonhatatlant!
Ha ilyenkor elszáll a gép, akkor a naplója alapján állítsa vissza az eredeti állapotot! Hasonlóan, mint az adatbázisoknál a tranzakció.
Amit Tso ír a "helyes" fájl írásról, pontosan azt kellene tennie a fájlrendszernek ilyen "hibás" esetben. Tehát, amikor csonkolásra megnyitok egy fájlt, akkor ne csonkoljon, hanem egy új területre kezdje el kiírni az adatokat, és amint jön egy flush() vagy close(), akkor átállítgathatja a linkeket, hogy most már nem ez a fájl, hanem az új az.
Azt szerintem senki sem várja el, hogy egy "tranzakció" (nyitás, írás, zárás) közbeni elszállás esetén az új adatok kiíródjanak részben is a fájlrendszerbe, de azt igen, hogy a régi adatok ne vesszenek el.
Mi a hiba a gondolatmenetemmel?

Az egesszel az a baj, hogy nincs hardver, ezert szoftver szinten sem atommi muvelet minden esetben, az aramkimaradas ellen biztosan semmi nem ved. Ha mondjuk minden gepben lenne egy kis UPS, ami biztositana, hogy a legutolso lemezirasi muveletek mindenkeppen kiirodnak a lemezre, akkor talan. Az egesznek tenyleg az a baja, hogy nincs biztosan atomi muvelet ezek kozul.

"és amint jön egy flush() vagy close(), akkor átállítgathatja a linkeket, hogy most már nem ez a fájl, hanem az új az."

Itt is siman el tud veszni az adat, hiszen a link atallitas nem atomi muvelet.
2 lepesbol all szoftverszinten:
1. rarakod az uj filera a linket.
2. a regi filera mutato linket leveszed.

Ezek mind lemezmueletek, amelyek a disk cache-ben tarolodnak, es azt, hogy valojaban a lemez mikor es milyen sorrendben hajtja vegre, nem tudod, ez lemez firmwaretol fugg.
Igy hiaba tetted meg mindket lepest, lehet, hogy a diszk firmware a kettes lepest elobb hajtja vegre, mint az egyest, mert neki fejmozgatasi szempontbol igy optimalis. Ha aramkimaradas van akkor igy meg tokmindegy, szoftverszinten mi van. Amig nincs aramkimaradas esetere olyan UPS-ed, ami biztositja, hogy akarmi tortenik, a diszk cache mindenkeppen kiirodik a lemezre, addig ez a modszer sem jo.

Ezt már akartam kérdezni, hogy vajon a szóba került lefagy a gép, resetet nyomok ill. hasonló műveleteknél mi történik a lemez cache-sel?

A merevlemez észleli a resetet és rögtön mindent elfelejt és széttárja a "kezét", vagy esetleg kiírja a cache-ben tárolt műveleteket/adatokat is?

Az egyik, amit rosszul gondolsz, hogy az ext3 filerendszer data=ordered módban csak a metaadatot naplózza. A file-ok tartalmát nem. Ahhoz data=journal módba kéne rakni, ami kb felére apasztaná a teljesítményét.
A másik, hogy a filerendszer nem adatbázis, nincsenek vele szemben olyan erős ACID követelmények, mint egy adatbázissal szemben. Pl. nincsenek benne tranzakciók. Ha neked valamire tranzakciók kellenek, akkor használj adatbázist. A filerendszer naplózással annyit ér csak el, hogy pl. a rename() atomi művelet lehessen.

Hasznos olvasnivaló a témában:
http://flamingspork.com/talks/2007/06/eat_my_data.odp

Megjegysés: a mai winchesterek nem írják ki azonnal az adatot, még akkor sem, ha direkt fsync-et használsz és visszaolvasod, ez ugyanis simán jöhet a winchester cache-ből. Ha az általad fsync-elt esemény között, de a winchester fizikai írása között száll el a gép, akkor nem tudsz mit tenni.

A fenti miatt nincs az a filerendszer, sőt még adatbázis-kezelő rendszer sem, amelyik garantálja a 100%-os biztonságot egy winchesteren (vagy akár egy géphez tartozó raid tömbön). Kb. ott kezdődik _a_ biztonság, hogy cluster FS, több gép, fizikailag távoli elhelyezés, stb...

Azért írtam idézőjelek közé, mert tisztában vagyok vele, hogy nem tényleges tranzakció. De az elve az kellene legyen. Amíg a program nem mondja, hogy itt kell az adatot menteni (flush, close), ami adatbáziséknál commit, addig a művelet abnormális befejezése esetén marad minden a régiben (adatbázisnál rollback).
Az én elvi megoldásomnál sincs adat naplózás, csak azt a metaadatot kell naplózni, hogy az adott fájl tartalma, hol van a merevlemezen. Amikor vége az írásnak, akkor állítja át a metadatot az új helynek megfelelően. Ez a megoldás nem csökkenti a teljesítményt.
Én csak az alap problémára írtam egy elképzelést (csonkolásra nyitás, mentés, zárás). Nyílván, ha egy fájl egy részének felülírása a probléma, akkor már más a helyzet, mert ott a biztonságos működéshez tényleg másolatot kellene (adat naplózás) csinálni az adott részről, ami teljesítmény veszteséggel jár. De erről én nem beszéltem.
Azt ext3-as példákat azért sem értem, mert ott nincs ez a probléma.

Én xfs-t használok. Ott pontosan ugyan ez a helyzet. Ott hozzátettek egy egyszerű mondatot a filerendszer használatához. Szünetmentes áramellátás erősen javasolt. Nekem egy notebookom van. Ez igy automatikusan megoldott. De ha valaki minden sebességet maximálisan ki akar használni az előbb utóbb csak a stabilitás rovására fokozható, anélkül, hogy a felhasználónak bármiféle lépést kelljen tennie. Jelen esetben egy szünetmentes táp.

10 éve a Postgres egy nagyságrenddel lassabb volt más adatbáziskezelőknél, pl. a mysql-nél. Írták a readme-ben, hogy ennek az az oka, hogy ők a tranzakciókat fsync-elik, a mysql viszont nem. Configolható volt az fsync, ki lehetett kapcsolni (attól felgyorsult), de ezt nem javasolták. Ezzel szemben a mostani Postgresben az fsync alapállapotban ki van kapcsolva. Változott a koncepció.

Mindezzel csak arra akarok rámutatni: Az fsync kérdés minimum nem egyértelmű, lehet rajta töprengeni. Túlzottan együgyű az az elgondolás, hogy amelyik alkalmazás nem fsynceli a fontos (?) adatait az bugos.

Egyébként, ahogy mások is írták, az fsync sem tudja garantálni az adat végleges rögzítését. Ez a manban is benne van, azt mindig érdemes olvasgatni.
--
CCC3

Komolyan nem értem a problémát. Biztos én vagyok szűk látókörű, de mi a gond azzal, hogy a nem kiírt fájlok tartalmát elveszti a fájlendszer áramszünetkor? Ez mindigis így volt, max most nőtt a valószínűsége, hogy többet várakozik. Na és? Akinek biztonság kell és még a fájlrendszer dokumentációját sem olvassa el és nem állítja be megfelelően a mount opciókat... annak tanulni kell egy kis adatvesztésből.
Ez a probléma nem érint sok programot, nem értem, hogy az említett gnome és kde miért irogat állandóan fájlokat (ez már eleve nem egy szimpatikus ötlet, flash memórián nem kedvező, de a merevlemez ébresztgetésének sem lehet örülni), de ha már így tesz számíthatna az adatvesztésre, mert ez eddig is könnyen előfrodulhatott csak most nagyobb a valószínüsége.
Valaki homályosítson fel.

A vita elsősorban abból indult ki, hogy az ilyen módon megnyitott fileok régebbi tartalma és a módosított tartalom is elveszik, 0 byte-os fileméretet produkálva.

Ha (a fentiek alapján) elgondolom, hogy pl. a szerkesztésre megnyitott dokumentum teljes mértékben kinullázódik, akkor elég idegesítő tulajdonságként képzelem el a dolgot... különösen, ha minden előzetes intézkedést semmibe véve esetleg egy programhiba okoz végzetes problémát...

Amitől összeomlik a rendszer úgy, hogy nem tudja még szinkronizálni sem a fájlrendszert, az nem egy mezei program hiba.
Akkor nullázódik ki ha lemented és 60sec-en belül fagy a rendszer vagy áramszünet utolér, eddig ez az idő 5sec volt alapértelmezetten (Ha jól értem).
Ez főleg akkor aggasztó, ha nincs a fontos fájlokról biztonsági másolat, de az önmagában is aggasztó.