Portál AbcLinuxu, 5. května 2025 13:19
Aktuální verze jádra: 3.10-rc4. Citáty týdne: Arnd Bergmann, Luc Verhaegen. Na cestě ke spolehlivému rešení OOM v užvatelském prostoru.
Aktuální vývojová verze jádra je 3.10-rc4 vydaná 2. června. rc4 je nicméně menší než rc3 (bomba!). Ale i tak by mohlo být ještě menší (fuuuj!). Je tam obvyklá hromada oprav v ovladačích (drm, pinctrl, scsi target, fbdev, xen), ale i v systémech souborů (cifs, xfs, drobné opravy v reiserfs a nfs)
Stabilní aktualizace: verze 3.2.46 vyšla 31. května.
Náš proces revidování kódu jednoznačně není dokonalý, jestliže musíme čekat, než se věci v linux-next porouchají, aby si lidé konečně všimli problémů.
Nedávno jsem se ze spolehlivého zdroje dozvěděl, že se managementu v ARM opravdu hodně nelíbí projekt ovladače Lima. Slušně se to dá říct tak, že nevidí na open source ovladači pro Mali žádné výhody a myslí si, že ovladač Lima už teď odhaluje příliš mnoho z vnitřností hardwaru Mali. Navíc je jejich postoj takový, že kdyby opravdu chtěli open source ovladač, tak by prostě jen zveřejnili svůj vlastní kód a bylo by.
Opravdu?
Návštěva od jaderného zabijáka při nedostatku paměti (OOM killer) je asi tak vítaná jako nečekná návštěva z berňáku. OOM killer je zavolán, jakmile systému dochází paměť a nemůže pokračovat dál bez zabití někerých procesů; jde o sadu často se měnících heuristik, které popisují, jaké procesy se mají zabít s co největším dopadem na uvolnění paměti a co nejmenším dopadem na systém jako celek. Člověk by řekl, že něco takového nelze dělat v uživatelském prostoru, ale jsou i uživatelé, kteří se snaží dosáhnout právě tohoto a dokonce se jim to i daří. Tak či tak není řešení OOM v uživatelském prostoru tak bezpečné, jako by někteří chtěli, ale není ani moc shoda na tom, jak to zlepšit.
Řešení OOM v uživatelském prostoru nejčastěji používá asi Google. Kvůli snaze vytlačit z hardwaru co nejvíce je u nich obvyklé toho na servery co nejvíce namačkat. Paměťové řídící skupiny (memcg) se tam používají k tomu, aby si uživatelé nepřekáželi. Stejně jako systém jako celek se i memcg může dostat do situace OOM (nedostatku paměti) a jádro reaguje stejným způsobem: probudí se OOM killer a začne zabíjet procesy v dané skupině. Ale protože situace OOM v řídící skupině neohrožuje stabilitu systému jako celku, tak má jádro v řešení této situace volnější ruku. OOM killer na úrovni řídící skupiny je možné úplně zakázat a navíc je to mechanismus, jak si proces může zažádat o notifikace pro případ, kdy ve skupině dojde paměť.
Zmiňovaný notifikační mechanismus je navržen podle potřeb globálního, pravděpodobně privilegovaného procesu, který spravuje několik skupin v systému; proces může reagovat zvýšením paměťového stropu, přesunem mezi skupinami nebo selektivím zabitím procesů. Ale v případě Googlu to funguje trochu jinak: každý interní uživatel u Google má možnost (a zodpovědnost) řešit situace OOM v rámci své skupiny. Tento přístup může fungovat, ale jsou tu nástrahy, kvůli kterým je to méně spolehlivé, než by někdo mohl doufat.
Jedním z důvodů je to, že jelikož si uživatelé řeší OOM sami, pak i OOM handler je omezen stejným paměťovým stropem. Takže pokud obsluha OOM bude potřebovat paměť navíc, bude blokována a jako ostatní procesy bude čekat na vyřešení situace; to je v podstatě deadlock celé skupiny. Dá se tomu vyhnout uzamčením stránek a tak podobně, ale i tak je docela obtížné napsat program, kde je záruka, že nedojde k alokacím paměti v jádře. K deadlocku může vést třeba i přečtení souboru v /proc (vyvolající alokaci paměti).
Dalším problémem je to, že proces, jehož alokace vyvolala situaci OOM, může být zrovna hluboko v jádře a držet určité množství zámků. Semafor mmap_sem se zdá být obzvláště problematický, protože je často zamknutý v situacích, kdy je paměť alokována – např. při obsluze výpadků stránek. Pokud obsluha OOM potřebuje udělat něco, co by mohlo potřebovat ty samé zámky, tak se bude čekat na nesprávný proces a opět dojde k deadlocku.
Výsledkem je tedy to, že OOM killing v uživatelském prostoru není 100% spolehlivý a snad ani nikdy nebude. Co se týče Google, pak lehce nespolehlivé očetřování OOM je přijatelné, ale deadlocky nikoliv. Proto v roce 2011 David Rientjes zaslal patch zavádějící nastavitelnou prodlevu OOM killeru. Při jejím nastavení má obsluha OOM v uživatelském prostoru určitý čas na vyřešení situace, jinak nastoupí jádro.
Davidův patch nebyl tehdy začleněn; ostatní z něj měli pocit, že je to jen obezlička pro chyby v uživatelském prostoru, které by bylo lepší opravit u zdroje. Tehdy David řekl, že Google bude patch v případě potřeby udržovat interně, ale domníval se, že v případě rozšíření memcg by i ostatní měli zájem o stejnou funkčnost. Teď se po dvou letech snaží znovu, ale reakce nejsou o moc jiné.
Někteří vývojáři reagovali, že mít obsluhu OOM uvnitř skupiny, kterou má řídit, je případem typu „tak takhle tedy ne“, ale jakmile David vysvětlil, že si uživatelé dělají vlastní obsluhu OOM, tak trochu ustoupili. I tak se ale drží názor, že by obsluha OOM měla být uzamčena v paměti a měla by se vyvarovat alokaci paměti. Zejména je pak pozdě číst soubory v /proc za účelem zjištění, co za procesy v systému běží, když paměť už došla. Alternativou je ale sledovat vytváření procesů v každé memcg, což s sebou nese vlastní (výkonnostní) problémy.
Johannes Weiner přišel s konstruktivními nápady, jak stávající situaci zlepšit. Jedním z nich byl patch, jenž měl vyřešit problém procesů čekajících na vyřešení OOM a držících zámky. Tento patch dělá dvě úpravy, první z nich se týká situací, kdy je alokace paměti přímým následkem systémového volání. V tomto případě alokující proces nebude vůbec umístěn do čekací fronty OOM; místo toho volání selže s chybou ENOMEM. To řeší většinu problému, ale část zůstává: systémová volání, která předtím fungovala, mohou najednou vracet neočekávaný chybový kód. To může vést k podivnému chování a jelikož je nedostatek paměti málo častý, pak by takové chování bylo obtížné odhalit při testování.
Druhá část patche mění cestu pro výpadek stránky. V tomto případě není možné skončit s chybou ENOMEM; to by vedlo ke smrti procesu s výpadkem. Kód je změněn tak, aby si tuto skutečnost zaznamenal a vrátil se; jakmile je call stack odrolován a všechny zámky jsou uvolněné, pak bude proces čekat na vyřešení problému OOM. S těmito změnami by většina (nebo veškeré) problémy s deadlocky měly snad zmizet.
To ale neřeší jiný problém: pokud se obsluha OOM pokusí sama alokovat paměť, dostane se do fronty čekajících procesů a opět dojde k deadlocku. Johannes navrhl, že obsluha OOM v uživatelském prostoru by mohla formálně sdělit svou roli jádru. Pak, jakmile by proces narazil na problém OOM, by jádro mohlo ověřit, jestli to je proces pro obsluhu; pokud ano, situace by byla předána k řešení jadernému OOM killeru. Výsledek by byl stejný jako s prodlevou, jen by k tomu došlo hned, bez čekání.
Michal Hocko má Johannesovy změny raději, ale měl dodatečný návrh: implementovat globální watchdog proces. Tento proces by obdržel upozornění na situace OOM současně jako obsluha uživatele; spustil by časovač a čekal by na vyřešení situace. Pokud by čas vypršel, pak by watchdog zabil uživatelovu obsluhu a povolil jaderné řešení OOM v dotčené memcg. Jeho názor je ten, že problém je možné řešit v uživatelském prostoru, a proto by i tam měl být vyřešen.
Při zvolení kombinace těchto úprav je možné, že deadlocky obsluhy OOM v uživatelském prostoru budou vyřešeny. V takovém případě už snad nebude mechanismus s prodlevou od Googlu potřeba. Ani to ale zajisté nebude konec debat o obsluze OOM; tato debata je asi nekonečná.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.