Cvičení v 7. týdnu

Jádro OS UNIX, parametry, využití procfs, kompilace jádra


Jádro OS UNIX

Jádro operačního systému je základní komponentou celého operačního systému. Zavádí se jako první ze všech komponent operačního systému, provádí inicializaci hardwaru počítače, vlastní inicializaci, startuje celý systém.

První jádra UNIXu byla monolitická, tzn. že celé jádro s veškerou svojí funkšností tvořilo jeden celek. V současné době je trend tzv. mikrojader (microkernel), kde toto vlastní jádro poskytuje jen nejnutnější funkce (meziprocesová komunikace, správa paměti), čímž je velice malé a kompaktní. Zbylé funkce jsou implementovány jako autonomní procesy, které s jádrem komunikují přes definované rozhraní. Tato architektura má několik nesporných výhod: je snadné ji udržovat, nové vlastnosti se přidávají velice jednoduše, atd. Tento systém má však také některé nedostatky. Vyvstává zde problém rozhraní mezi komponentami, také meziprocesová komunikace je rozsáhlejší než pouhé volání funkce uvnitř jádra. Tím je systém pomalejší než monolitická jádra. Toto zpomalení je však v současných systémech akceptovatelné a je vykoupené jednodušší systémovou udžbou.

Jádro LINUXu bylo vyvíjeno na i386 architektuře, která byla považována za dolní hranici pro rozumný UNIXový systém. Primární snahou bylo dosažení rozumného výkonu a jednoduchosti, proto byla původní jádra LINUXu monolitická. V současné době se jádro LINUXu řadí mezi hybridní jádra. Některé komponenty jádra se stávají samostatnými (moduly), mají částečně definované rozhraní a lze je vyvíjet samostatně, čímž se jádro přibližuje architektuře mikrojader. Na druhou stranu se však modul po zavedení stává integrální součástí jádra, takže jádro ve své podstatě stále zůstává monolitické.

Činnost jádra
Hlavním úlohou jádra je poskytování služeb aplikačním procesům. Proto je jádro umístěno na nejnižší úrovni ze všech sw komponent systému. Mezi jeho úkoly patří:

Veškeré služby, které jádro poskytuje, jsou zpřístupněny přes systémová volání.

Runtime parametry jádra

Při zavádění systému je možné předat jádru systému LINUX parametry, které ovlivňují jeho chod. Tyto parametry jsou podobné parametrům příkazové řádky klasických programů. Parametry předáváme pomocí zavaděče linuxu, což je v našem případě GRUB. V době zobrazení GRUB menu je možné stisknout A a editovat seznam parametrů jádra. Pozor na použití mezer - mezery oddělují parametry, nikoli hodnoty jediného parametru. Např.:

        ether=9,0x300,0xd0000,0xd4000,eth0  root=/dev/hda1            // Správně
        ether = 9, 0x300, 0xd0000, 0xd4000, eth0  root = /dev/hda1    // Špatně

Některé z parametrů jsou zpracovány přímo jádrem, ostatní jsou později předány procesu init jako argumenty. V okamžiku, kdy již systém běží, je možné zjistit původní příkazovou řádku jádra ze souboru /proc/cmdline.

Formát parametrů:
Většina parametrů má tvar name[=value_1][,value_2]...[,value_11]. Jádro se nejdříve snaží zpracovat parametry: root=, ro, rw a debug. Dále zpracuje všechny parametry týkající se jednotlivých ovladačů aktuálně zakompilovaných v jádře. Ze zbylých parametrů vybere všechny ve tvaru name=value a interpretuje je jako nastavení proměnné prostředí (např. TERM=vt100 nebo BOOT_IMAGE=vmlinuz.bak). Zbylé nezpracované parametry jsou předány procesu init jako argument (např. samostatná číslice na příkazové řádce nebude zpracována jádrem, ale předá se jako argument procesu init, který ji interpretuje jako žádost o přechod do stejnojmenného runlevelu).

Zde je uveden přehled některých parametrů:

ParametrVýznam
debugumožňuje výpis ladících hlášek jádra
root=specifikuje zařízení (partition) odkud má připojit kořenový (/) systém souborů
ro, rwexplicitně určuje, jakým způsobem je kořenový systém souborů připojen
vga=nastavení implicitního rozlišení obrazovky (VGA mód)
ether=nastavení parametrů (base address, IRQ, ...) pro síťovou kartu
init=Program, který se spustí jako první, místo programu init.
ip=A:B:C:D:E:F:G Nastavení TCP/IP rozhraní: A=IP_adresa, pokud A není zadáno použije se RARP/BOOTP/DHCP. Pokud je zadáno B, získává adresu jen ze serveru B. C=default_router, D=netmask, E=hostname, F=interface (eth0, eth1, atd.), G=protokol autokonfigurace, tj. slovíčko RARP nebo BOOTP nebo DHCP nebo nic.

Příklad 1: Boot do textového režimu s hustšími řádky (80x50zn).
Řešení: Předáme jádru parametr vga=0x0f01 nebo vga=ask (viz /usr/src/linux/Documentation/svga.txt)

Úkol 1: Nabootujte virtuální stroj do single-user módu. Jaký parametr předáte jádru? Kdo parametr zpracuje? Jak vypadá soubor /proc/cmdline?

Úkol 2: Jak nastartujete systém do použitelného stavu, pokud je poškozen soubor /etc/passwd (tzn. ani root se nemůže přihlásit)? Použijte parametr init=

proc file system

Proc file system je speciální souborový systém, který umožňuje získávat některé aktuální informace z jádra. Jedná se především o informace o běžících procesech, konfiguraci počítače, době běhu systému, atd. Ačkoliv se veškeré informace získávají ze souborů nebo adresářů, nejsou nikde na disku uloženy. Obsah souborového systému je dynamicky generován jádrem zvlášť pro každý požadavek na čtení (či zápis). Proc file system se stejně jako jiné souborové systémy připojuje příkazem mount. Připojovací bod je obvykle adresář proc.

Úkol 3: Projděte adresářovou strukturu /proc a zjistěte dobu běhu systému, rozdělení disku, informace o paměti, aktuálně připojené souborové systémy, zátěž systému, informace o procesoru a parametry jádra, se kterými bylo spuštěno. Soubory v procfs na Linuxu jsou textové a můžete je vypisovat např programem cat. Nepoužívejte program less, který provádí operaci seek(), jenž na virtuálních souborech nefunguje správně.

Úkol 4: Přepněte do single-user módu (příkazem init 1) a odpojte /proc. Pozorujte, jak se chovají některé programy (ps, uname, top, ...).

Úkol 5: Spusťte příkaz sleep na pozadí s několika přesměrováními:

sleep 1000 > file1 2> file2 3> file3 &
ps
Příkazem ps (ve stejném okně) vypište PID běžícího procesu sleep a prozkoumejte jeho adresář /proc/PID/. Všiměte si obsahu souborů cmdline, status, symbolického linku cwd, který ukazuje na aktuální adresář procesu. Všiměte si obsahu podadresáře fd. Tam jsou symbolické linky na jednotlivé soubory aktuálně otevřené procesem.

Kompilace jádra

Jádro může obsahovat velké množství kódu pro nějaký konkrétní hardware, který často není instalován a ani v daných podmínkách instalován nikdy nebude. Jádro je pak zbytečně velké a pomalé. Kromě toho zabírá operační paměť, kterou by jinak bylo možné efektivně využít. Jádro je vždy přítomno v operační paměti celé (neswapuje se), proto je jeho velikost pro efektivitu využití paměti podstatná. To jsou hlavní důvody, proč si uživatelé Linuxu často překládají vlastní jádro. Při překladu je důležité vědět, které části jádra jsou nutné k běhu v dané konfiguraci hardware, aby pak nedošlo k situaci, kdy sice jádro bude přeložené a relativně funkční, ale právě některá podstatná vlastnost přeložena nebude a jádro pro daný účel bude nepoužitelné.

Vlastní postup přeložení jádra sestává z několika kroků. Prvním z nich je získání zdrojových textů jádra. Ty je možné získat z ftp.kernel.org v /pub/linux/kernel/vx.y, kde x.y je označení verze. Celé číslo verze má tvar x.y.z .Verze, kde y je liché číslo jsou vývojové verze, jejichž stabilita není zaručena. Verze se sudým y jsou verze produkční, tedy "stabilní". Zdrojové kódy jádra se dle konvence ukládají do adresářů /usr/src/linux-x.y.z. Symbolický link /usr/src/linux pak ukazuje na aktuální verzi - tu, kterou chceme překládat. Pro překlad jádra je nutné přepnout se do adresáře, kde jsou zdrojové texty (např. cd /usr/src/linux).

Nejprve je nutné jádro nakonfigurovat. Je to proces, při kterém se určuje, které komponenty a jak mají být přeloženy. Vynecháte-li některou nezbytnou komponentu, jádro nebude funkční. Přidáte-li něco navíc, vznikne universálnější jádro, které však bude větší, zabere víc paměti za běhu a bude i pomalejší. Na instalačních CD-ROM Linuxu bývají velká jádra s podporou všeho možného. Přeložením vlastního jádra se zefektivní využití paměti a zrychlí systém.

Pro konfiguraci je možné použít příkaz make menuconfig v textovém modu, nebo make xconfig v X-windows. Dalším krokem je příkaz make clean, kdy jsou odstraněny veškeré dříve překompilované objektové soubory.

Poslením krokem je vlatní překlad jádra. Tento krok trvá nejdéle, protože teprve teď se provádí vlastní překlad, na starších procesorech může trvat i několi desítek minut. Pro tuto činnost je možné použít příkaz make bzImage. Výsledné jádro bude uloženo v podadresáři arch/i386/boot pod jménem bzImage.

Přeložené jádro obsahuje implicitní hodnoty některých runtime parametrů (např. root FS, videomód, ...). Tyto implicitní hodnoty lze trvale změnit přímo v souboru bzImage programem rdev.

Pokud byla do jádra zahrnuta podpora modulů a některé z modulů byly nastaveny, je nutné tyto moduly také přeložit. To se provádí příkazem make modules a příkaz make modules_install překopíruje přeložené moduly do adresáře /lib/modules/x.y.z/, kde jsou připraveny pro připojování k jádru za běhu.

Instalace jádra:
Proto, aby vše fungovalo, je nutné systém nastavit tak, aby používal nové jádro. Jádro nejprve nakopírujeme na cílové místo:

cp /usr/src/linux-x.y.z/arch/i386/boot/bzImage /boot/bzImage-x.y.z
V případě zavaděče GRUB je třeba upravit jeho konfiguraci /etc/grub.conf a přidat další položku do GRUB-menu.

Překlad jádra v učebně K310
Zdrojové texty jádra si stáhněte ze serveru OS. Příkaz make mrproper vyčistí, ale nepoškrábe - tedy smaže vše, co se dá znova vytvořit, včetně aktuální konfigurace - souboru .config.

Překlad provedeme takto:


	make mrproper        # vymaže konfiguraci (při změně konf. se nedělá)
	make menuconfig      # příp. make config, make xconfig
	make clean           # vymaže binární soubory z minulého překladu
	make                 # nebo make bzImage - vlastní překlad
	make modules_install # zkopírování modulů do /lib/modules/<verze jádra>
Poté, co je jádro přeloženo, zkopírujte jej do /boot a upravte GRUB.

Bodovaný úkol 6 (2 body): Vyzkoušejte překlad jádra podle uvedeného postupu nové jádro nabootujte.