Správa linuxového serveru: Úvod do kompilace jádra a modulů

Minulý díl probral kompilaci softwaru obecně, včetně začlenění ručně zkompilovaného softwaru do balíčkovacího systému. Dnešní díl se podívá na zoubek problematice kompilace patrně nejrozsáhlejšího softwaru, který v linuxových distribucích naleznete. Je jím samotné jádro, srdce operačního systému.

Úvod

Na úvod opět upozorňuji na první dva díly (první díldruhý díl) tohoto „miniseriálu“ o kompilaci, které doporučuji mít přečtené, než se pustíte do čtení tohoto dílu. V případě linuxového jádra platí všechny nevýhody ruční kompilace, které byly v těchto předchozích dílech zmíněny, dokonce lze i jednu přidat – nesprávně nastavené jádro může server odstavit (systém již nenaběhne) a jedinou opravou je nabootování staršího jádra.

Lekce z anatomie: Jádro, moduly a initrd

Jádro (kernel) je část operačního systému, která je zodpovědná za přidělování systémových prostředků procesům, hardwarovou abstrakci, správu a plánování procesů, správu paměti atd. Linux představuje nejčastěji používané jádro (a také jediné možné, má-li jít o linuxovou distribuci), i když existují i jiná jádra použitelná s projektem GNU. Jen tak pro zajímavost, Debian má kupříkladu k dispozici i variantu s jádrem z FreeBSD (Debian GNU/kFreeBSD) či s jádrem Hurd (Debian GNU/Hurd). V tomto seriálu se ale budu zabývat výhradně jádrem Linux.

Jádro jako takové je jedna jediná binárka, která obvykle sídlí v adresáři /boot. Často se označuje jako vmlinuz. V adresáři /boot může vedle sebe existovat mnoho verzí jader, přičemž je na zavaděči, aby konkrétní jádro po spuštění počítače zavedl do paměti a spustil. Linuxové zavaděče samozřejmě nemají problém se zaváděním různých jader podle toho, které si obsluha počítače zvolí při jeho startu.

Jádro sice může, ale také nemusí, mít veškerou funkčnost schovanou ve výše zmíněné binárce. Různé ovladače zařízení či specifické funkce mohou být zkompilovány jako moduly, které pak mohou být za běhu systému podle potřeby zavedeny nebo i odstraněny. Tyto moduly jsou k dispozici v příslušném podadresáři (jehož název odpovídá verzi použitého jádra) v /lib/modules.

Asi si teď říkáte, jak může systém naběhnout, pokud klíčový modul není součástí jádra, ale pouze jako modul. Tuto situaci nejlépe osvětlí příklad. Jádru dává zavaděč v podobě parametru informaci o tom, kde se nachází kořenový souborový systém, který má připojit. Jádro jej připojí a spustí /sbin/init, který pak zavede celý zbytek systému. Umístěním pro kořenový adresář může být třeba druhý oddíl prvního disku /dev/sda2. K tomu, aby tuto operaci jádro mohlo provést, musí ovšem umět pracovat s diskovým řadičem, ke kterému je disk připojen, a souborovým systémem, který je pro daný oddíl (/dev/sda2) použit. Co když však některý z těchto ovladačů bude zkompilován jako modul? V takovém případě by se k němu jádro nemohlo dostat a výsledkem by byl „kernel panic“.

Tento problém elegantně řeší iniciální ramdisk, malý, zkomprimovaný souborový systém, uložený také v adresáři /boot (v Debianu pod názvem initrd.img s příponou v podobě verze použitého jádra), který obsahuje všechny potřebné moduly a nástroje k zavedení systému. Distribuce této možnosti hojně využívají a obsahují nástroje k jeho snadnému vygenerování. Iniciální ramdisk samozřejmě nepotřebujete, pokud vaše jádro obsahuje všechny potřebné moduly (čehož můžete dosáhnout kompilací vlastního jádra) a také pokud pro zavedení systému není třeba provést ještě něco speciálního (jako se např. dotázat uživatele na heslo šifrovaného oddílu, kde se systém nachází).

Proč kompilovat jádro?

Pokud nepoužíváte source-based distribuci jako Gentoo, asi příliš důvodů pro odklon od distribučního jádra mít nebudete. Distribuční jádra bývají modulární, tzn. maximum funkcionality a ovladačů je dostupné v modulech, které můžete za běhu systému do jádra nahrát nebo naopak z jádra vyjmout (k tomu slouží nástroje jako lsmod a modprobe). Nemáte-li v distribučním jádru k dispozici určitý modul, není kvůli tomu třeba kompilovat celé jádro, stačí zkompilovat pouze příslušný modul (podmínkou je dostupnost zdrojového kódu jádra, který lze snadno doinstalovat pomocí správce balíčků).

Proč si tedy kompilovat vlastní jádro? Ideální je, pokud se můžete spokojit s distribučním a ušetřit si tak nejen kompilaci, ale také sledování bezpečnostních problémů a následnou rekompilaci, jakmile se objeví nějaká zranitelnost. Existují ovšem situace, kdy se vám kompilace může vyplatit.

Patche

Patch jako takový představuje úpravu zdrojového kódu jádra oproti oficiální verzi. Oficiální verze softwaru (v tomto případě jádra), která nebyla nijak upravena, se označuje jako „vanilla“. Distribuční jádra téměř vždy aplikují vlastní patche, ať už to jsou úpravy funkčnosti nebo opravy chyb, které byly zpětně portovány pro stabilní verzi jádra dané distribuce.

Podstatné je, že příslušné patche je třeba aplikovat na zdrojový kód, tzn. před samotnou kompilací. Tudíž, pokud vámi zvolená distribuce zahrnula patch, který použít nechcete, nebo naopak nezahrnula patch, který použít chcete, nemáte jinou možnost než zkompilovat jádro ručně a aplikovat ty patche, které chcete.

Existuje řada úprav jádra, které přidávají nové vlastnosti nebo optimalizují jeho použití pro konkrétní účel. Některé z nich se časem dostanou do jádra a jeho vývojáři se o ně budou starat, jiným zůstává z mnoha důvodů neoficiální statut a patchování představuje jedinou možnost, jak tuto funkcionalitu dostat do vámi používaného jádra. Takovýchto patchů pro Linux existuje mnoho. Na desktopech je to např. plánovač BFS Cona Kolivase, který by měl vylepšovat odezvu a výkon na obyčejných domácích počítačích (nikoliv na serverech s mnoha procesory).

Na serveru existuje rovněž mnoho možností. Jednu kategorii tvoří bezpečnostní patche jako např. grsecurity či TOMOYO, které jsou sice neoficiální (nebo částečně neoficiální jako TOMOYO), ale mohou nabídnout jednodušší konfiguraci nebo jinou sadu vlastností než v jádře vestavěný SELinux. Další kategorii tvoří virtualizační patche, které implementují různé druhy virtualizace (Xen, OpenVZ, VServer apod.). Možností je mnoho.

Některá jádra s příslušnými patchi (např. patche týkající se virtualizace) již distribuce mívají v repozitářích, takže rozhodně doporučuji se podívat, jestli náhodou nemáte jádro s již aplikovaným požadovaným patchem. Můžete také narazit na neoficiální repozitář s dalšími patchovanými jádry přímo pro vaši distribuci. V případě neoficiálních repozitářů je však obezřetnost určitě na místě. Nejde jenom o bezpečnost, ale také o dostatečně zodpovědný přístup správce daného repozitáře, abyste po instalaci příslušného jádra nezjistili, že dotyčný se na měsíc odmlčel, a vy máte už tři týdny v neoficiálním jádře nezáplatovanou bezpečnostní díru, která právě začíná být masivně zneužívána.

Nastavení

Nastavení vlastností jádra je druhá oblast, kvůli které se může vyplatit jádro zkompilovat. Distribuce se přirozeně snaží zvolit takové nastavení, které bude vyhovovat co nejvíce lidem, ale už z podstaty věci není možné se zavděčit všem. Některá nastavení kupříkladu sice mohou přidávat zajímavé vlastnosti, ale současně třeba snižují výkon. Správci distribucí pak mají dilema – zahrnout vlastnost, která zaujme např. deset procent správců serverů, ale všem ostatním, byť o pár procent, poklesne výkon. Podobně je to s veškerými optimalizacemi, popřípadě kompilacemi přímo pro daný typ procesoru. Distribuce volí takové nastavení, které poběží na co největším spektru hardwaru, což znemožňuje použití optimalizací pro konkrétní typ procesoru.

Vanilla nebo distribuční kernel?

Kompilovat můžete jak distribuční jádro (zdrojáky bývají k dispozici jako samostatný balíček), tak vanilla jádro, které si stáhnete z kernel.org. Vývojáři udržují více stabilních verzí jádra, přičemž některé větve mají dokonce dlouhodobou podporu. Volba je v tomto případě samozřejmě na vás. Novější jádra obvykle vylepšují podporu hardwaru a opravují chyby, ale mohou obsahovat i regrese (což v programátorském žargonu znamená „dříve nám to fungovalo, ale mezi tím to někdo rozbil“).

Použít distribuční verzi jádra může být v tomto směru výhodnější – jednak neobjevíte regrese (s největší pravděpodobností) a jednak se vám bude dostávat jeho oprav po dobu života distribuce.

Tím bych tento díl ukončil. Příště vám představím kompilaci jádra z praktického pohledu.