Portál AbcLinuxu, 5. května 2025 16:54
Aktuální verze jádra: 2.6.30-rc3. Citáty týdne: Linus Torvalds, Stephen Hemminger,. USB a rychlé bootování. O hodnotě statických sledovacích bodů. Odbočka: Statické sledovací body. Neshoda. KSM to zkouší znovu.
Současné vývojové jádro je stále 2.6.30-rc3; během minulého týdne nebyly vydány žádné předverze. Do repozitáře hlavní řady stále proudí změny; téměř výhradně jde o opravy, ale také je zde obnovení Tuxe jako jaderného maskota (vizte Jádro má nové logo).
Současné stabilní jádro 2.6 je 2.6.29.2 vydané 27. dubna s okolo 100 patchi. V tomto vydání je mnoho oprav, které se týkají celého stromu. Přinejmenším několik z nich má dopad na bezpečnost (např. af_rose, agp, fs_mask kvalifikací, splice/ocfs2). Jako obvykle je doporučeno aktualizovat.
-- Linus Torvalds vrací Tuxe do jádra
-- Al Viro
Změny, které se dělají, aby Linux bootoval rychleji, jsou obecně vítány, ale když vedou ke zjevné regresi, ozývají se stížnosti. K této situaci došlo, když Jeff Garzik ohlásil regresi, kvůli které jeden z jeho systémů přestal bootovat. Kvůli některým změnám v tom, jak se inicializuje USB, systém již nerozpoznal jeho disky a nemohl z nich připojit kořenový souborový systém. Jak se ukazuje, problém není omezen na disky a ani není nový; jde o dlouho známý souběh, který většina hardwaru dříve „předběhla“, ale nyní stejný hardware často závod prohrává.
Jeff problém hledal dělením půlením a vysledoval ho ke konkrétnímu commitu ze září 2008. Nový kód, místo toho, aby 100 ms spal jako součást inicializace každého USB hubu, používá mechanismus zpožděné práce, kterým naplánuje další inicializační krok na 100 ms do budoucnosti. Pro jádra, která mají zakompilovaný USB kód, to umožňuje, aby bootovací vlákno dělalo jinou práci místo blokování a čekání na tyto pauzy. To mělo vcelku pozitivní dopad na rychlost bootování, autor patche Alan Stern hlásil:
Z Jeffovy perspektivy je problém v tom, že jeho systém úspěšně nabotooval s každým jádrem do 2.6.28. Okamžitý návrh bylo použít jadernou bootovací volbu rootdelay, která zpozdí proces bootování o daný počet sekund předtím, než se pokusí připojit kořenový souborový systém. To se Jeffovi příliš nelíbilo, takže se zeptal: Odkdy je přípustné nechat regrese výměnou za rychlost?
Jak se ukazuje, Jeff měl dříve pouze „štěstí“, na tento problém mohl s jiným hardwarem narazit u dřívějších jader, jak upozornil Greg Kroah-Hartman: Co se stane, když si koupíš nový stroj s více hostitelskými USB řadiči a rychlejším procesorem? To samé. Tento problém je specifický pro USB, protože stará inicializace čekala 100 ms za každou USB sběrnici (tj. kořenový hub) synchronně, takže systém s pěti huby čekal 500 ms předtím, než začal načítat připojená zařízení. Nový kód provádí stejnou inicializaci paralelně.
I když je relativně vzácné mít kořenový souborový systém na USB, rozhodně to není neslýchané. Embedded systémy jsou poměrně jasný kandidát, vzhledem k ceně a velikosti, jak objasnil Alan Cox. Několik distribucí má také podporu pro kompletní běh z USB zařízení, typicky USB flash disku.
Jak ale říkají Jeff a další, uživatelé (či distribuce), kteří aktualizují svá jádra, ale nepřidají volbu rootdelay, riskují, že budou mít systémy, které nenabootují. USB je nicméně zásadně odlišná od ostatních sběrnic, protože neexistuje způsob, jak zjistit, že je vyčíslování zařízení na konkrétním hubu hotové. Mark Lord toto vysvětlení zpochybnil s poznámkou: SATA diskům také trvá proměnnou dobu, než se při bootu „objeví“. Jak ale vysvětlil Arjan van de Ven, je zde významný rozdíl:
Ukazuje se, že se stejný problém v trochu jiném vzezření ukazuje u embedded zařízení, která používají USB konzole. David VomLehn pracuje na patchi, který čeká, než je k dispozici USB konzole. Vzhledem k tomu, že embedded zařízení mají USB konzole, ale pouze pro vývoj a ladění, dlouhé zpoždění čekáním na konzoli je ve většině případů nechtěné. Nicméně protože není možné zjistit, že byla všechna USB zařízení již ohlášena, nějaké zpoždění je nevyhnutelné. Davidův mechanismus by čekal do časového limitu specifikovaného jaderným bootovacím parametrem, na rozdíl od rootdelay by se nicméně probudil v okamžiku, kdy se konzole detekuje.
Jak David poznamenává, problém jde dál, postihuje i USB síťová zařízení potřebná při bootu. Diskuze o různých verzích patche také poukázala na to, že podobné problémy existují i pro jiné sběrnice. Jak se zlepšuje – a rozšiřuje – paralelizace bootu, bude objeveno více problémů tohoto druhu. Je tedy potřeba nalézt obecnější řešení pro čekání na zařízení, která je potřeba objevit předtím, než je možné bootovat, jak popisuje Arjan:
Prozatím byly problémy pouze identifikovány a diskutovány. Možnosti, jak je obejít (jako rootdelay) byly zmíněny, ale to „řeší“ pouze jednu stranu problému. Distribuce dodávají nebo budou dodávat jádra 2.6.29 ve svých nadcházejících vydáních a jeden doufá, že tento problém již řešily, jinak může být poměrně mnoho poněkud zmatených uživatelů, jejichž systémy nenabootují. Je důležité, aby problémy, alespoň pro USB úložná zařízení, byly vyřešeny v 2.6.31.
Jak je v současnosti velmi dobře známo, linuxové jádro postrádá ten druh sledovacích možností, které lze najít v jiných unixových jádrech. Tato mezera není výsledkem nedostatku snahy, v minulosti ale vývojáři snažící se dostat do jádra sledovací infrastrukturu často narazili na mnoho překážek, včetně opozice svých kolegů, kteří tuto infrastrukturu nepovažovali za přínosnou a odmítali její režii. V poslední době se zdá, že zvýšený zájem o sledování vývojářům pomohl překonat některé z těchto námitek; současná diskuze nicméně ukazuje, že obavy ze sledování stále žijí a mají potenciál vykolejit přidání sledovacích nástrojů do jádra.
DTrace od Sunu je známý a dynamický sledovací nástroj; to znamená, že jej lze použít k vložení sledovacího bodu (téměř) kamkoliv do jádra. Jádro Solarisu se nicméně dodává s rozsáhlou a dobře zdokumentovanou sadu statických sledovacích bodů, které lze aktivovat podle jména. Tyto sledovací body byly umístěny do pečlivě vybraných míst, která umožňují zkoumat to, co jádro skutečně dělá. Mnoho skutečně nasazovaných skriptů pro DTrace si vystačí pouze se statickými sledovacími body a nepotřebují žádné dynamické vkládání.
Statické sledovací body mají zjevnou hodnotu. Reprezentují znalosti vývojářů, kteří (předpokládejme) daný jaderný subsystém znají nejlépe. Správci systémů je mohou využít k tomu, aby získali velké množství užitečných informací bez nutnosti znát kód. Dobře umístěné statické sledovací body přinášejí do jádra významné množství transparentnosti. Jak se sledovací schopnosti Linuxu zlepšují, vývojáři přirozeně chtějí poskytnout podobnou sadu sledovacích bodů. Fakt, že statické sledování je rozumně dobře podporováno (pomocí FTrace) v jádrech hlavní řady – s rozsáhlejší podporou dostupnou se SystemTapem a LTTng – také podporuje vytváření statických sledovacích bodů. Výsledkem je, že se nedávno objevily patche, které přidávají sledovací body mezi jinými do pracovních front a některých vnitřních funkcí správy paměti.
Stojí za to udělat odbočku a podívat se na to, jakou podobu statické sledovací body mají; návrh linuxových sledovacích bodů poskytuje náhled na problémy, které měly řešit. Jako příklad vezměme následující sledovací body pro kód správy paměti, který hlásí alokace stránek. Deklarace sledovacích bodů vypadá takto:
#include <linux/tracepoint.h> TRACE_EVENT(mm_page_allocation, TP_PROTO(unsigned long pfn, unsigned long free), TP_ARGS(pfn, free), TP_STRUCT__entry( __field(unsigned long, pfn) __field(unsigned long, free) ), TP_fast_assign( __entry->pfn = pfn; __entry->free = free; ), TP_printk("pfn=%lx zone_free=%ld", __entry->pfn, __entry->free) );
Vypadá to jako spousta textu kvůli něčemu, co je v jistém smyslu přepínatelné volání printk(). Přirozeně má ale každý kousek svůj důvod. Makro TRACE_EVENT() deklaruje sledovací bod – tento se jmenuje mm_page_allocation – ale nevytváří kód. Sledovací bod má argumenty, které jsou předány jeho skutečné konkretizaci (ke které se dostaneme níže); ty jsou plně deklarovány makrem TP_PROTO() a vyjmenovány makrem TP_ARGS(). Ve stručnosti TP_PROTO() poskytuje sledovacímu bodu prototyp funkce, zatímco TP_ARGS() vypadá jako volání tohoto sledovacího bodu.
Tyto hodnoty jsou dostatečné k tomu, aby programátor mohl vložit do kódu sledovací bod řádkem, jako je tento:
trace_mm_page_allocation(page_to_pfn(page), zone_page_state(zone, NR_FREE_PAGES));
Tento sledovací bod je ve skutečnosti pouze známý bod v kódu, do kterého lze za běhu vložit jeden nebo více ukazatelů na funkce podporované jadernými sledovacími nástroji jako SystemTap či Ftrace. Když je sledovací bod povolen, všechny funkce v něm uložené budou zavolány s předanými argumenty. V tomto případě povolení sledovacího bodu vyústí ve volání, kdykoliv je alokována stránka; tato volání obdrží jako parametry číslo rámce stránky alokované stránky a počet zbývajících volných stránek.
Jak lze vidět z deklarace výše, na sledovacím bodě je toho víc než tyto argumenty; zbytek informací z deklarace sledovacího bodu využívá subsystém Ftrace. Ftrace má pár zdánlivě neslučitelných cílů; chce být schopen poskytnout čitelný výstup ze sledovacího bodu bez potřeby dalších nástrojů, ale vývojáři Ftrace také chtějí být schopni exportovat data ze sledování jádra rychle, bez režie jejich kódování. A tady přichází místo, kde se objevují zbývající parametry TRACE_EVENT().
Když je správně definována (v několika hlavičkových souborech v kernel/trace jsou k tomu připravena kouzla), přidává TP_STRUCT__entry() struktuře, která reprezentuje sledovací bod, další pole; tato pole by měla být schopna uložit binární parametry spojené se sledovacím bodem. Makro TP_fast_assign() poskytuje kód potřebný pro kopírování relevantních dat do této struktury. Tato data mohou být, s několika změnami, které byly začleněny do 2.6.30, exportována v binárním formátu do uživatelského prostoru. Jestliže ale uživatel chce vidět formátované informace, makro TP_printk() poskytuje formátovací řetězec a argumenty potřebné k tomu, aby se to dalo zařídit.
Vzhledem ke všem řečem o sledování v minulých letech je zde jasný požadavek mít tento druh sledovacího nástroje v jádře. Jeden by si tedy myslel, že přidávání sledovacích bodů nebude kontroverzní. Přirozeně to není tak jednoduché.
První námitka, která se obvykle objeví, souvisí s výkonnostním dopadem sledovacích bodů, které jsou často umisťovány do pro výkonnost nejkritičtějších kódových cest v jádře. Tam se koneckonců odehrává skutečná akce. Přidání nepodmíněného volání funkce kvůli implementaci sledovacího bodu je nepřípustné; dokonce i vložení testu if okolo volání je problematické. Po doslova letech práce vývojáři přišli se schématem, které zahrnuje patchování kódu za běhu které redukuje výkonnostní dopady neaktivního sledovacího bodu z praktického pohledu na nulu. I ti nejvíce na výkon zaměření vývojáři se ohledně této záležitosti přestali rozčilovat. Nicméně tu samozřejmě jsou další.
Účelem sledovacího bodu je poskytnout specifickou informaci z jádra uživatelskému prostoru. V určitém ohledu se tedy takový bod stává jaderným ABI. A jako ABI je sledovací bod vytesán do kamene, jakmile je dodán ve stabilním jádře. Není všeobecná shoda o neměnnosti jaderných sledovacích bodů, ale jednoduchý fakt je takový, že jakmile sledovací bod prokáže svou užitečnost a začne se používat, jeho změna způsobí, že se sledovací nástroje v uživatelském prostoru rozbijí. To znamená, že i když sledovací body nejsou považovány za tak stabilní ABI jako systémová volání, jejich změny stále vyvolají nezanedbatelný odpor.
Udržovat sledovací body stabilní, když se kód kolem nich bude měnit, bude obtížné. Významná část jaderné komunity tyto sledovací body nikdy používat nebude, takže o nich ani nebudou vědět a nevšimnou si, když se rozbijí. Ale i vývojář, který se bude snažit udržovat sledovací body stabilní, narazí na problémy, když se kód vyvine tak, že původní sledovací bod nebude již dávat smysl. Lze si představit tu hromadu kódu, kterou bude potřeba přidat, aby sledovací body poskytovaly iluzi úplně jiné sady rozhodnutí, která provádějí v budoucích jádrech; lze si také představit nepřátelské přijetí, jakého se každému takovému kódu dostane.
Břemeno údržby spojené se sledovacími body je důvodem opozice Andrewa Mortona proti jejich přidávání. Ohledně sledovacích bodů pracovních front Andrew řekl:
Není třeba říkat, že vývojáři sledování považují svůj kód za využívanější. Frederic Weisbecker poskytl detailní popis ladění, které lze provést se sledovacími body pracovních front. Odpověď Inga Molnára se zdá být pokusem pozastavit přidávání dalších jaderných možností sledování, dokud nebude vyřešena otázka sledovacích bodů. Andrew nicméně přesvědčen není; zdá se, že by byl raději, kdyby většinu této práce zařídily dynamické sledovací nástroje.
V době psaní tohoto článku věci stojí takto. Jestliže se tyto sledovací body do hlavní řady nedostanou, je těžké si představit, že by vývojáři v budoucnu vytvářeli další. Linux tak může skončit bez sady dobře definovaných statických sledovacích bodů po ještě dlouhou dobu – i když by nebylo překvapivé, kdyby dodavatelé podnikových jader nějaké do vlastních jader přidávali. Možná je to výsledek, který jaderná komunita jako celek chce, ale není jasné, jestli je tento pocit momentálně všeobecný. Jestliže naopak Linux skončí s rozumnou sadou sledovacích bodů, vývojová komunita bude muset přijít s nějakým konsenzem o tom, jaké druhy sledovacích nástrojů jsou přijatelné.
V listopadu Jaderné noviny zkoumaly patch KSM (kernel shared memory, paměť nasdílená jádrem). KSM bylo vytvořeno jako řešení problému, na který se naráží u systémů, kde běží virtualizovaní hosté: Tyto systémy mají v paměti velké množství stránek, které obsahují stejná data, ale jádro nemá žádný způsob, jakým by hostům umožnilo tyto stránky sdílet. Kód KSM prohledává paměť a hledá páry stránek, které obsahují identická data; když je takový pár nalezen, je sloučen do jedné stránky mapované do obou pozic. Stránky jsou označovány jako kopírovat při zápisu [copy-on-write], takže je jádro automaticky oddělí v případě, že jeden proces modifikuje svá data.
O účelu tohoto patche byly nějaké obavy, ale brzy se ukázalo, že KSM může pomoci ušetřit významné množství paměti. KSM ale nebylo začleněno kvůli dvěma dalším problémům. Jedním z nich, diskutovaným převážně za zavřenými dveřmi, se zdá být obava z používání SHA1 hashů k porovnávání stránek. Pokud by se útočníkovi podařilo vytvořit kolizi hashů, mohl by být schopen podstrčit vlastní data (nebo kód) procesu patřícímu jinému uživateli a/nebo virtuálnímu stroji. Další problém se týká jiného druhu útočníka: VMWare drží patent na algoritmus, který vypadá velmi podobně jako metoda, kterou používaly první patche KSM. Existuje důkaz, že tento patent by bylo možné zrušit díky dřívější implementaci [prior art], ale to je bitva, kterou nikdo nechce vybojovat.
KSM na chvíli zmizelo ze scény poté, co se tyto záležitosti objevily, ale v nedávné době byla k revizi zaslána nová verze KSM patchů. Rychlý pohled na kód ukazuje, že na obě tyto obavy bylo reagováno – a dokonce že vývojáři KSM byli schopni zabít obě mouchy jednou ranou. Všechno je záležitostí odstranění hashů stránek.
Patent 6.789.156 není zrovna lehké čtení; obsahuje celých 74 nároků. Většina nezávislých nároků má nicméně jednu věc společnou: Zahrnují výpočet hodnoty hashe, aby se našly identické stránky v systému. Pokud by se kód KSM dokázal vyhnout hashům stránek, tyto nároky by zjevně neporušoval. A, jak je popsáno výše, využívání hashování také vytváří nějaké bezpečnostní obavy. Vývojářům KSM (a právníkům, se kterými mluvili) tedy muselo být jasné, že hashe musí zmizet.
Současné patche KSM nahradily tabulky hashů dvěma oddělenými červeno-černými stromy. Stránky sledované KSM jsou zpočátku uloženy v „nestabilním stromě“; termín „nestabilní“ znamená, že KSM považuje jejich obsah za nestálý. Umístění ve stromě je určeno jednoduchým memcmp() obsahu stránky; stránka je v podstatě považována za obrovské číslo a podle toho zařazena. Nestabilní strom je vhodný pro hledání stránek s duplicitním obsahem; relativně rychlé procházení stromem ukáže kandidáty.
Stojí za to poznamenat, že KSM neumisťuje každou stránku, kterou prohledá, do nestabilního stromu. Pokud se obsah stránky během cyklu prohledávání paměti změní, stránka stejně není dobrým kandidátem pro sdílení. Stránky, u kterých byly zpozorovány změny, tedy v nestabilním stromě nejsou reprezentovány. Nestabilní strom je také po každém cyklu prohledávání zahozen a vytvořen odzačátku. To řeší problém se stránkami, které jsou kvůli modifikacím ve stromě na špatném místě. Povaha červeno-černého stromu znamená, že prohledávání a vkládání jsou v podstatě stejné operace, takže cena za znovuvybudování celého stromu od začátku v každém cyklu je malá.
Další stránky, které se nenacházejí v nestabilním stromě, jsou ty, které byly skutečně spojeny se svými duplikáty. Vzhledem k tomu, že jsou sdílené stránky označeny jako pouze pro čtení, KSM ví, že jejich obsah se změnit nemůže. Tyto stránky jsou umístěny do odděleného „stabilního stromu“. Stabilní strom je také červeno-černý strom, ale vzhledem k tomu, že stránka se zde nemůže změnou ocitnout na nesprávném místě, není potřeba ho pravidelně znovuvytvářet. Jakmile se stránka dostane do stabilního stromu, zůstává tam, dokud ji buď někdo nemodifikuje, nebo ji neodmapují všichni uživatelé.
Výsledný systém zjevně funguje. Vyhození hashů může znamenat cenu v podobě o něco vyšších nároků na využití CPU a paměti; nebyly zaslány žádné benchmarky, které by ukazovaly rozdíl. Na systémech, které KSM nevyužívají vůbec, nicméně není cena žádná a v každém případě může za danou cenu stát to, že se zamezí potenciálním problémům s používáním tabulek hashů k identifikaci stránek s identickým obsahem. V tomto okamžiku se komentáře ke kódu KSM většinou zabývají relativně malými detaily. Tento kód bude dost možná připraven k začlenění do jádra 2.6.31.
(Dodatek: Jonathan, autor článku, výše psal, že „většina“ nezávislých nároků v patentu VMWare vyžaduje použití mechanismu hashování. Ve skutečnosti je několik nároků, které tento požadavek nemají, ale nahrazují ho jedním nebo dvěma dalšími. Některé nároky pokrývají používání stránek s kopírováním při zápisu, ale ty všechny explicitně říkají, že tato technika se používá u stránek s „relativně vysokou pravděpodobností budoucí modifikace“. V tomto případě ale nemá příliš smysl takové stránky sdílet; KSM je – tím, že je vypouští z nestabilního stromu – zcela ignoruje. Zbývající nároky popisují dělení paměti do „tříd“, což KSM nedělá.)
Super překlad citátu od Stephena Hemmingera
A já si myslel, že heshe slouží pouze pro rychlé rozpoznání stránek s jistě různým obsahem a jen u stránek se stejným hashem se provede srovnání obsahu (memcmp). Díky tomu by nemohlo dojít k záměrnému či náhodnému podstrčení jiných dat se stejným hashem.To jsem si myslel taky.
Ale mělo by vyhrát lepší řešení a ne rozhodovat podle toho, že nějaká firmička si zapatentovala něco co bylo v té době již známé a dokonce i implementované (z mého pohledu ukradla cizí myšlenku pro případné patentové útoky v budoucnu).+1
USB je nicméně zásadně odlišná od ostatních sběrnic, protože neexistuje způsob, jak zjistit, že je vyčíslování zařízení na konkrétním hubu hotové.Tak to je teda USBčko dost debilní...
obava z používání SHA1 hashů k porovnávání stránek. Pokud by se útočníkovi podařilo vytvořit kolizi hashů (...)No a nemůžou se teda použít dvě hashe? Třeba sha1 + md[4|5|6] nebo nějaký crc nebo checksum či tak něco. Imho by pak bylo prakticky nemožné najít použitelnou kolizi...
Nedalo by se na root prostě třeba nějak počkat? Dejme tomu, že jádro ve chvíli, kdy se chce na root fs podívat zjistí, že není k dispozici. V té chvíli by třeba mohlo počkat nějakých 100ms a zkusit to znovu, páč mezitím by se USB doenumerovalo, ne?Dalo, dokonce je to v článku popsáno.
rootdelay
? Ne, to je něco jinýho. Imho rootdelay
není vůbec dobrý nápad, tím se celý problém akorát zesložití. Nebo je to v textu jinde, co stále přehlížím...?
Nedalo by se na root prostě třeba nějak počkat? Dejme tomu, že jádro ve chvíli, kdy se chce na root fs podívat zjistí, že není k dispozici. V té chvíli by třeba mohlo počkat nějakých 100ms a zkusit to znovu, páč mezitím by se USB doenumerovalo, ne?Možná by stačilo někde držet flag, že ještě běží enumerace, takže jádro by zkoušelo připojit root tak dlouho, dokud by byla naděje, že se zařízení zjeví. Jinak z mých zkušeností se zcela statickým jádrem na mém HTPC dělá největší zpožnění při startu jádra USB a (PATA) IDE. Zatímco u IDE jde jádru domluvit, aby nehledalo neexistující zařízení a tím boot kapičku urychlit, u USB bohužel nic takového není možné. Kdyby se jádru dal předal parametr, na jaký systém nemá při bootování čekat, dal by tím se urychlit start u systémů, které nebootují z USB (což je, za běžných okolností, většina).
takže jádro by zkoušelo připojit root tak dlouho, dokud by byla naděje, že se zařízení zjeví.Jasně, pokus o připojení rootu, pokud selže, počkat třeba 100ms, pak další pokus. Pokud celkový čas přesáhne počet USB root hubů * 100ms, vzdát to.
Chválím autora za krásný jazyk.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.