Počítače

Btrfs vrací do jádra Linuxu pojistku COW fixup, bez které hrozí tichá ztráta dat

Souborový systém btrfs přišel v jádře Linuxu 7.2 o pojistku jménem COW fixup, protože se zdálo, že příčinu mezitím odstranila správa paměti. Ukázalo se to na hostiteli virtuálních strojů v IBM, kde se hosté s pamětí uloženou v souboru na btrfs zasekli na hodiny. Záplatu, která mechanismus vrací zpátky, přijal Linus Torvalds 6. srpna, krátce před vydáním 7.2-rc7.

· 4 zhlédnutí

Otevřený 2,5palcový pevný disk s viditelnou plotnou a raménkem čtecí hlavy
Tichá ztráta dat znamená, že se zápis na disk vůbec nedostane a nikdo se to nedozví. Na snímku je otevřený 2,5palcový disk Toshiba MK6465GSX. Foto: Brian Wong, Wikimedia Commons (CC BY-SA 2.0)

K čemu byl COW fixup

Když aplikace zapíše do souboru na btrfs, projde ten zápis odloženou alokací: souborový systém si rezervuje místo, založí takzvaný ordered extent, tedy záznam o chystaném zápisu, a teprve potom data putují na disk. Drží se u toho pravidlo, že každý blok označený za změněný má buď rezervaci, nebo ordered extent. Jenže stránku v paměti umí označit za změněnou i kód mimo souborový systém. Pak rezervace chybí a zápis nemá kam jít.

Přesně pro tyhle případy přibyl do btrfs v roce 2008 asynchronní pomocník, který chybějící rezervaci dodělá dřív, než se blok pošle na disk. To je COW fixup.

Proč se rušil

Qu Wenruo ze SUSE napsal 14. dubna záplatu, která mechanismus odstranila. Argumentoval tím, že chyby ve funkci get_user_pages(), kvůli kterým fixup vznikl, vyřešila správa paměti zavedením pin_user_pages(). V experimentálních sestaveních se navíc takové zápisy už delší dobu rovnou odmítaly a fungovalo to.

Druhý důvod mířil dopředu: původní fixup uměl jen celé stránky a nepočítal s tím, že blok souborového systému může být menší než folio, tedy než skupina stránek, se kterou jádro pracuje jako s jedním celkem. To překáželo práci na velkých foliích. V popisu záplaty přitom Qu Wenruo přiznal, že warningy, které mu při vstřikování chyb do cesty vstupu a výstupu naskakovaly, vysvětlit neuměl: podle vlastních slov se mu příčinu nepodařilo najít. David Sterba záplatu zařadil 8. června a do hlavní větve se dostala v otevíracím okně jádra 7.2.

Hosté KVM na s390 se zasekli na hodiny

21. července ohlásil Christian Borntraeger z IBM do konference linux-btrfs, že jim v denních testech náhodně tuhnou virtuální stroje, jejichž paměť leží v souboru na btrfs. Na hostiteli s390 s jádrem 7.2.0-rc3 uvázly ve stavu D dvě vlákna vCPU, obsluha irqfd, dva pracovníci zápisu, khugepaged i volání syncfs z balíčkovače dnf, a to na hodiny.

Rozbor výpisu paměti ukázal jediné folio o 64 stránkách, tedy 256 kB, patřící souboru s pamětí hosta o velikosti 1,25 GB. Zůstal na něm viset zámek, bitmapa změněných bloků byla prázdná a žádný zápis na disk neběžel.

Přímé čtení do sdílené mapy

Souběh za tím popsal Boris Burkov v záplatě, která fixup vrací. Folio je sdíleně namapované do paměti procesu a zároveň slouží jako cíl čtení s přímým přístupem. Čtení na začátku vidí folio jako změněné, takže ho jen připne a samo neoznačuje. Než ale doběhne, btrfs stihne folio uložit na disk a označit za čisté. Dokončení čtení pak folio označí za změněné znovu, tentokrát mimo souborový systém a bez rezervace.

Qu Wenruo k tomu 25. července poslal do sady testů fstests regresní test a popsal projevy střízlivěji než pozdější pull request: zaseknutý zápis dat, nebo přepnutí souborového systému do režimu jen pro čtení. Stačí k tomu čtení s přímým přístupem do namapovaného rozsahu a současné volání sync_range nad ním. U běžného btrfs, kde má blok i stránka 4 kB, jde podle něj o regresi v 7.2; u bloku menšího než stránka se to neošetřilo nikdy.

Návrat, ale postavený jinak

Burkovova záplata starý kód nevrací. Detekce se přesunula z ukládání na disk do funkce dirty_folio(), tedy do okamžiku, kdy někdo folio zvenčí označí za změněné. Ta událost nenese rozsah, takže se za podezřelé označí všechny dosud čisté bloky folia uvnitř souboru. Ukládání je pak přeskočí a předá pomocníkovi, který dodělá rezervaci, a běžný zápis, který mezitím rozsah pokryje, příznak zruší.

Sledovat se to musí po blocích, ne po foliích. Burkov v popisu rozebírá případ, kdy jedna půlka folia čeká na zápis do už rezervovaného ordered extentu a druhá potřebuje fixup: kdo to nerozliší, buď zapíše nerezervovaná data, nebo se zablokuje. Dohromady jsou to dva commity a 651 přidaných řádků v osmi souborech, přičemž polovina je podle Sterby ladicí a pomocný kód. Jako recenzent je pod ní podepsaný Qu Wenruo, tedy autor odstranění, a commit nese značku Assisted-by: LLM. Borntraeger už v hlášení napsal, že mu s rozborem výpisu i s návrhem opravy pomáhal jazykový model.

Kdy to bude ve vydání

Sterba změnu poslal Torvaldsovi 6. srpna jako samostatný pull request a ostatní opravy týdne oddělil do druhého se slovy, že je to pro jistotu (přeloženo z angličtiny). Pull request s fixupem přijal Torvalds ještě týž večer. Označkované vydání 7.2-rc7 v neděli dopoledne ještě nebylo, kód už ale v hlavní větvi je; stabilní jádro 7.2 vyjde podle Phoronixu ještě v srpnu.

Odstranění fixupu mělo uvolnit cestu velkým foliím a ta cesta zůstala volná i po jeho návratu: nový mechanismus s bloky menšími než folio počítá od začátku, na rozdíl od toho z roku 2008. Zaplatilo se za to tím, že regrese seděla v jádře od prvního kandidáta 7.2 do šestého, a 651 řádky nového kódu v sedmém, tedy ve fázi, kdy se do jádra obvykle přidávají jednořádkové opravy.

Počítače

LinuxBtrfsJádro LinuxuSouborové systémyKVM

Diskuse

Zatím tu nikdo nediskutuje.

Diskutovat mohou přihlášení čtenáři – přihlaste se nebo si založte účet.

← zpět na výpis