Hlavní navigace

Jak zakázat explicitní fsync (v Ubuntu)

9. 6. 2012 23:46 (aktualizováno) | Ondřej Novák

Sync, fsync, fdatasync, díváte se na jednu trojici z mnoha zel, které na linuxu občas potkávám. Tyto příkazy obecně mají zaručovat programu, že všechny data která do souboru zapsal, budou fyzicky zapsána na disk. A teď by se mohlo diskutovat o tom, jestli vůbec má uživatelská aplikace (čili program běžící v userspace) právo takto přímo manipulovat s HW daného počítače. Ano, všechny tři příkazy nařizují operačnímu systému, aby syncnul cache s diskem, zpravidla aby vysypal obsah dirty stránek v cache na disk a to okamžitě, bez ohledu na to, co zrovna operační system dělá.

Nebudete mi věřit, ale už jsem se setkal s filesystemem, který častý fsync dokonale položí. Ne, nezhroutí se, ale stane se nepoužitelným. Je to btrfs, který používám zejména kvůli schopnosti vytvářet subvolumy a také kvůli kompresi, což se zejména pro SSD disky zasouvané do USBčka (flash disky), celkem hodí. Ony ty flashky nejsou nějak extra rychlé, ale se zapnutou kompresí se s tím dá celkem bez problému žít.

Nechci otvírat diskuzi, zda fsync ano, nebo ne. Já si myslím, že ne, že aplikace nemá co kecat do nastavení operačního systému a jeho politiky práce s diskem. Diskové cache jsou pro aplikaci transparentní a to i ve vztahu s jinými aplikacemi, takže i bez explicitního syncování by měl být obsah souborů koherentní.

Jak tedy vypnout fsync na linuxu? A jde to vůbec? Nebudu k tomu potřebovat nějaké speciální dovednosti, jako například schopnost kompilovat jádro? Naštěstí to není tak těžké. Na níže uvedený postup jsem narazil, když jsem hledal důvod, proč dpkg je na btrfs tak pomalé. Postupně jsem vygooglil několik návodů, všechny založené na knihovně, kterou budeme načítat pomocí LD_PRELOAD. Knihovnu si lze jednoduše vyrobit.

libnosync.c

#include <unistd.h>

void sync (void) {
}

int syncfs (int fd) {
 return 0;
}

int fsync (int fd) {
 return 0;
}

int fdatasync (int fd) {
 return 0;
}

Kód přeložíme příkazem:

gcc -O2 -s -Wall -fPIC -shared -o libnosync.so libnosync.c

A jako root si jej nakopírujeme například do /usr/local/lib/libnosync.so

Aplikace, kterým chceme zakázat používání fsync a spol, budeme spouštět přes nastavenou proměnnou LD_PRELOAD

LD_PRELOAD=/usr/local/lib/libnosync.so apt-get install ubuntu-desktop

(mimochodem, bez libnosync se ubunu-desktop na btrfs instaluje klidně i několik hodin, po zapnutí libnosync to zvládne za několik minut).

Zkusil jsem s tím experimentovat a takto jsem si pustil Firefox. A vida, najednou je Firefox svižný i na flashce, a vůbec se mi nestává, že by na několik desítek sekund tuhnul (s vysokým I/O) při přecházení mezi stránkami, nebo pouštění videa. Po menší upravě (zvětšení) limitů dirty_pages a spol. (viz /proc/sys/vm/…), už ani nepoznám, že jedu přes flashku.

Šlo by tuhle knihovnu vnutit každému spuštěnému programu tak, abych se explicitního syncování zbavil nadobro…?

Teď stop! Určitě někoho napadla otázka, zda takový zásah nebude mít vliv na stabilitu celého systému. Je nutné si uvědomit, že vypnutí explicitního syncování pomocí knihovny nebylo syncování zrušeno nadobro. Pořád má operační systém možnost syncovat při uzavírání souborů, při otevření souboru se zapnutým O_SYNC a samozřejmě, že explicitně syncovat může i jádro (umount, atd). Takže si nemyslím, že by to mohlo ohrozit stabilitu systému. Maximálně tak stabilitu některých aplikací – i když, takový rozbitý dpkg není žádný terno.

Napadla mě spousta šíleností, například rvát LD_PRELOAD do .bashrc, dále do .xinitrc… do /etc/profile nebo /etc/environment. Všude to nefungovalo úplně dobře, zpravidla se zrychlilo jen něco, ale například dpkg spouštěný přes synaptic spuštěný přes sudo dál jel svou šnečí rychlosti. Nakonec jsem v man ld.so objevil zmínku o souboru /etc/ld.so.preload. Nyní již máte dostatek indicií, abyste přišli na to, co s tím dál.

Tenhle soubor ve standardní instalaci nenajdete. Ale přes strace zjistíte, že se hledá. Pokud jej vytvoříte a vložíte do něj cestu na knihovnu „so“, bude se poctivě načítat pro každý spuštěný proces. To si lze také ověřit přes strace.