Práce v prostředí ramdisku
Zavaděč
O spuštění zavaděče se stará BIOS (resp. UEFI) počítače.
Nejrozšířenějším linuxovým zavaděčem je v současné době GRUB2, který má oproti staršímu zavaděči LILO výhodu především v tom, že jeho zaváděcí proces je velmi podobný tomu, jak funguje zavádění linuxového systému.
- BIOS
- BIOS sáhne vždy na první sektor blokového zařízení (tzv. MBR - Master Boot Record), kde se pokusí najít informaci o tom, odkud a kolik bajtů dat má natáhnout do paměti. Poté předá další řízení načtenému kódu.
- UEFI
- Supluje roli zavaděče a umožňuje zavést přímo jádro operačního systému. Předpokládá, že jádro je uloženo na diskovém oddíle se souborovým systémem FAT, ve formě binárního souboru. Místo binárního jádra OS mu lze předhodit zavaděč.
Více místa bylo mezi začátkem diskového oddílu a začátkem souborového systému (cca 66 kB). Toho využívala první verze zavaděče GRUB, která si na začátek disku uložila pouze malou část kódu, která si pak místo BIOSu natáhla do paměti vlastní kód zavaděče, uložený na začátku některého z diskových oddílů.
Tento koncept však přestal být s rostoucím množstvím existujícího hardware neudržitelný, protože nebylo možné do tak malého prostoru vtěsnat všechny potřebné ovladače. GRUB2, který nahradil původní verzi, používá podobný modulární koncept, jako linuxový kernel.
Na začátku disku je uloženo jádro s ovladači pro zpřístupnění adresáře s moduly a pak už lze natahovat moduly podle potřeby buďto manuálně z prostředí integrovaného shellu, nebo prostřednictvím konfiguračního souboru grub.cfg (GRUB legacy používal menu.lst).
Integrovaný shell, který umožňuje v průběhu zaváděcího procesu opravit případnou chybu v konfiguračním souboru je jednou z největších výhod zavaděče GRUB.
Pro bezdiskové zavádění je ale vhodnější použít zavaděč, který umožňuje zavádět jádro přes PXE, např. PXELINUX. GRUB2 sice také umí použít PXE, ale bohužel pouze pro bezdiskové zavedení potřebných modulů pro zavedení lokálního systému. |
Zavedení jádra
Zavaděč si lze představit jako jednoúčelový operační systém, který má za úkol:
- rozbalit jádro operačního systému do paměti počítače..
- spustit ho..
- ..a přitom mu předat případné parametry.
Jádro je spustitelný binární soubor, který poběží - na rozdíl od zavaděče - po celý čas běhu operačního systému.
Zavaděč jádro z úložiště přebírá ve formě samorozbalovacího archívu, jehož jméno podle obvyklého úzu začíná řetězcem vmlinuz. Toto pojmenování je závazné pouze do té míry, aby ho pod ním zavaděč v úložišti našel.
Jádro se rozbalí do paměti a od zavaděče převezme případné konfigurační volby. Pak se pokusí identifikovat a připojit zařízení, na kterém má být uložen operační systém a z něj spustit spouštěč dalších procesů - init. Aby to bylo možné, musí mít k dispozici všechny potřebné ovladače. Aby se jádro obešlo bez ramdisku, musí mít v sobě tyto ovladače zakompilované na tvrdo.
U distribucí, které si kompilují jádro na míru podle aktuální konfigurace stroje, s tím obvykle není problém. Ovšem u distribucí, které mají mít univerzální použití, by optimální konfigurace takového jádra mohla představovat neřešitelný problém. Proto se u nich využívá při zavádění tzv. RAM disk.
- Monolitické jádro
- Nepotřebuje ramdisk protože je kompilované na míru a obsahuje pouze potřebné ovladače. Má výhodu v tom, že může být lépe optimalizované a tím pádem i o něco výkonnější.
- Modulární jádro
- Nemusí využívat ramdisk, pokud má potřebné ovladače k dispozici. Výhoda ramdisku je však v tom, že mu stačí pouze základní ovladače potřebné pro rozbalení a připojení ramdisku. Ostatní ovladače jsou uloženy ve formě jaderných modulů v ramdisku a do jádra se zavádějí pouze v případě že jsou zatřebí. Takové jádro je tedy mnohem více flexibilní z hlediska diverzity hardware.
Prostředí RAM disku
Je čistě technicky vzato další kus operační paměti (odtud RAM disk), kam si jádro vybalí z komprimovaného cpio archívu minimalistické linuxové prostředí. Jádro s ním pak pracuje jako by šlo o normální systémový disk. Tzn. že si jej připojí, a spustí z něj init
.
V tomto případě však nejde o binární spouštěč procesů, ale shellový skript, který postupně spouští další skripty. Z hlediska zavádění systému je podstatné, že skript init
obsahuje podmínky, které umožňují proces zavádění cíleně přerušit.
K takovému přerušení zaváděcího procesu obvykle dojde, když některý ze spouštěcích skriptů vrátí chybu.
Prostředí a nástroje v ramdisku, umožňují zjistit příčinu chyby a případně provést její opravu. Někdy ale může být v okamžiku selhání příliš pozdě na to zjišťovat kde je problém, proto je dobré vědět:
- Jak cíleně přerušit zaváděcí proces v určité fázi zavádění.
- Co všechno lze v prostředí ramdisku dělat.
- Jak rozbalit obsah ramdisku, resp. vypsat jeho obsah.
- Jak dostat do ramdisku chybějící jaderné moduly
- Jak přidat do ramdisku další užitečné nástroje
- Jak přidat do ramdisku vlastní zaváděcí skript
- Jak restartovat stroj z prostředí ramdisku
Přerušení zaváděcího procesu
Přerušení zaváděcího procesu lze záměrně docílit tím, že se přes zavaděč předá jádru před jeho zavedením volba break.
vmlinuz... break=premount ...
Že jsme v prostředí ramdisku se pozná tak, že se místo obvyklého přihlášení rovnou objeví textová konzole
(initramfs)
Pokud konzoli opustíme příkazem exit, bude zaváděcí proces dál pokračovat.
Skript init , který je v kořeni ramdisku, se generuje na základě konfigurace v souboru /etc/initramfs-tools/initramfs.conf při sestavení souboru initrd. Ostatní skripty, které má ramdisk v adresáři /scripts . Se při jeho sestavení, či aktualizaci kopírují z adresáře /etc/initramfs-tools/scripts .
|
top
Parametr #top přeruší zaváděcí proces před spuštěním prvního skriptu. Jediná operace, která se realizuje dřív, je načtení obsahu paměti z disku, pokud byl systém při předchozím spuštění uspán na disk.
Během této fáze jádro provádí inicializaci existujících fyzických zařízení. Ty se přitom ohlašují svým specifickým kódem, na jehož základě jádro provádí identifikaci a natažení příslušného ovladače.
Protože k zařízení může existovat více ovladačů, které pochopitelně nelze používat současně, je součástí ramdisku adresář /etc/modprobe.d
, s konfiguračními soubory k jaderným modulům, ve kterých může být použití konfliktních modulů zakázáno.
Může se však vyskytnout situace, kdy některý z automaticky natahovaných modulů obsahuje chybu, která vede ke hroucení jádra. Pro takové případy akceptuje jádro seznam zakázaných modulů předaný zavaděčem prostřednictvím volby blacklist
vmlinuz... blacklist="xfs jfs ceph" ...
I když pak může být do určité míry systém omezen, můžeme jej dostat do stavu kdy se dá problém vyřešit.
Tabulka, podle které jádro provádí tuto identifikaci se generuje před(!) sestavením, či aktualizací ramdisku příkazem depmod |
modules
Parametrem #modules se přeruší zavádění předtím, než init
zavolá funkci load_modules. Ta zavede do jádra další moduly, které nemusí být bezprostředně vázané na konkrétní hardware, ale mohou být nezbytné pro další zavádění systému.
Seznam těchto modulů může být uložen rovnou v ramdisku - soubor /conf/modules
, ale také předán jádru prostřednictvím zavaděče
vmlinuz... modules="aufs reisefs" ...
premount
Kromě jaderných modulů a skriptů, které řídí zaváděcí proces, obsahuje ramdisk také nástroje a utility, co umožňují zavést systém ze sdíleného NFS adresáře, sestavit RAID pole, nahodit LVM skupinu, používat kryptovaný souborový systém, opravit poškozený souborový systém aj.
V této fázi tedy probíhají přípravy na to, aby ho bylo možné připojit zařízení kterém je uložen systém.
Protože v tomto bodě vzniká při zavádění nečastěji problém, je parametr #premount výchozím pro volbu break, je-li uvedena bez parametru. |
mount
Cestu k zařízení, na kterém má být uložen zaváděný systém, jádru předává zavaděč jako parametr volby root
.
vmlinuz... root=/dev/sda1 ...
Skript init
hodnotu /dev/sda1
uloží do proměnné ${ROOT}
, která se před přepnutím do finálního systému zruší. V prostředí ramdisku si lze vypsat přes echo.
Během předchozí fáze mělo být zařízení připraveno a nyní se ho init
pokusí připojit. Pokud se mu to nedaří, umožňuje přerušení ve fázi #mount zjistit proč.
Nejprve je třeba zkontrolovat obsah proměnné ${ROOT}
. Jeví-li se v pořádku, je třeba zjistit, zda-li příslušné zařízení skutečně existuje.
Pokud ne, tak to může znamenat že..
- jádru chybí potřebný ovladač (po kompilaci modulu nebyl aplikován depmod a zaktualizován příslušný ramdisk)
- nebo došlo k přejmenování zařízení (kupř. po přidání dalšího blokového zařízení do počítače, či při změně pořadí diskových oddílů)
- nebo z nějakého důvodu nedošlo k sestavení příslušného blokového zařízení (v případě RAID pole či LVM skupiny)
Některé zavaděče, jako např. GRUB, umožňují parametr volby root změnit ještě před spuštěním zaváděcího procesu, ale jsou situace, kdy to udělat nelze a je třeba úpravu provést v ramdisku.
|
Jednou z příčin, proč se nepodaří zařízení připojit, může být poškozený souborový systém. Proto musí být součástí ramdisku také nástroje, které ho umožňují opravit.
Pokud v něm chybí, pak to znamená, že je během sestavení ramdisku neměl systém k dispozici. V takovém případě je třeba nejprve souborový systém opravit jiným způsobem. A pak přes chroot provést aktualizaci ramdisku |
bottom
Většinu souborových systémů nelze opravit, pokud se s nimi pracuje. Systém uložený v ramdisku je tak ideálním prostředím pro takové operaci, protože
init
Na závěr přepne do finálního systému a spustí z něj /sbin/init
Konfigurace sítě
Konfigurace síťového rozhraní je u bezdiskového systému základním předpokladem pro úspěšné namountování systémového disku. Provádí ji podle parametrů předaných jádru skript /scripts/nfs
během fáze mount - těsně předtím, než se pokusí o namountování o systémového disku vypublikovaného přes NFS server.
Selhat může z následujících příčin:
- chybí ovladač síťového rozhraní
- síťové rozhraní je připojeno do subnetu, který nemá přístup na NFS server
- Pro IP adresu klientské stanice není do adresáře na NFS serveru povolen přístup
- V konfiguraci síťové karty, nebo v cestě ke vzdálenému adresáři je chyba
Nastavení síťě pomocí ipconfig
u diskless stroje
Skript volá shellové funkce, které pro nastavení sítě používají utilitu ipconfig, což je staticky linkovaná binárka (součást balíku klibc-utils), která však umožňuje nastavit pouze IPv4 konektivitu!. A to buď staticky, nebo s využitím DHCP[1].
Síťová konfigurace rozhraní přes které má být NFS připojeno se předává jádru s prefixem "ip=" nebo "nfsaddrs=". Z hlediska použití mezi nimi není rozdíl, neboť v případě "nfsaddrs=" jde pouze o relikt. Výsledek je v obou případech stejný.
Jaký je aktuální obsah proměnných ramdisku si lze ověřit příkazem env. Nastavení sítě pak můžeme provést předáním proměnné utilitě ipconfig.
(initramfs) ipconfig ${ip}
Pokud chceme použít jiné nastavení, než je obsahem této proměnné, můžeme ho vypsat manuálně. Syntaxe je stejná, jako když se předává parametrem "ip=" jádru při zavádění.
(initramfs) ipconfig -t 2 147.32.87.200:147.32.87.255:147.32.87.129:255.255.255.128:diskless:eth0:none IP-Config: eth0 hardware address be:be:be:01:71:12 mtu 1500 IP-Config: eth0 guessed broadcast address 147.32,87,255 IP-Config: eth0 complete (from 147.32.87.255): address: 147.32.87.200 broadcast: 147.32.87.255 netmask: 255.255.255.128 gateway: 147.32.87.200 dns0 : 0.0.0.0 dns1 host : diskless rootserver: 147.32.87.255 rootpath: filename :
Zda-li došlo k nastavení síťového rozhraní můžeme zjistit příkazy ifconfig nebo ip
147.32.87.200 - IPv4 adresa stroje 147.32.87.255 - IPv4 adresa NFS serveru (broadcast) 147.32.87.129 - gateway 255.255.255.128 - maska diskless - hostname stroje eth0 - síťové rozhraní none - použitá metoda
Chybí-li nastavení pro lo zařízení, lze provést konfiguraci takto:
(initramfs) ipconfig 127.0.0.1:::::lo:none
|
Nastavení IPv4 adresy síťového rozhraní s využitím DHCP
(initramfs) ipconfig -t 2 -c dhcp eth0
Nastavení IPv4 adres na více síťových rozhraní současně
(initramfs) ipconfig -c any eth0 eth1 192.168.1.1:::::eth2:none
Nastavení IPv6 adresy pomocí ip
Protože ipconfig umí pracovat pouze s IPv4 je nutné pro nastavení IPv6 adresy použít utilitu ip (součást balíku iproute2)
(initramfs) ip route add 2001:718:2:1612::/64 dev eth0 (initramfs) ip route add fe80::/64 dev eth0 (initramfs) ip route add default via fe80::7272:cfff:fe1b:d243 dev eth0 (initramfs) ip -6 route
Tuto utilitu by pochopitelně bylo možné použít také u diskless strojů. Vyžadovalo by to však manuální úpravu skriptů v ramdisku. Nicméně pro úplnost uvádím také použití této utility pro nastavení IPv4 adresy
(initramfs) ip address add 147.32.87.216/25 dev eth0 (initramfs) ip link set eth0 up (initramfs) ip route add default via 147.32.87.129 dev eth0
Debug ramdisku
vmlinuz... debug ...
Úpravy ramdisku
Pro práci s ramdiskem jsou určeny nástroje z balíku initramfs-tools
. Ale lze si poradit i bez nástrojů z tohoto balíku - pomocí běžně dostupných systémových utilit.
Výpis obsahu ramdisku
Pro výpis obsahu ramdisku lze použít nástroj lsinitramfs. Pokud ale není k dispozici, stačí vědět, že ramdisk je v podstatě pouze zkomprimovaný cpio archív
zcat /boot/initrd.img-3.2.0-2-686-pae | cpio -t
Rozbalení ramdisku
Pokud si chceme důkladněji prozkoumat obsah ramdisku, tak si ho můžeme vybalit do samostatného adresáře
zcat /boot/initrd.img-3.7.7 | cpio -i
Zabalení ramdisku
Po případných úpravách ho pak zase můžeme zabalit - pro jistotu do nového souboru
find . | cpio -o -H newc | gzip > /boot/initrd.img-3.7.7-upraveny
Korektní sestavení ramdisku u Debianu
Výše uvedené postupy je dobré znát, ale pro korektní sestavení ramdisku je rozumnější používat nástroj update-initramfs z balíku initramfs-tools
. Ten totiž zajistí - na základě konfigurace - aby sestavený ramdisk obsahoval vše potřebné i po každé aktualizaci, bez toho, že by bylo nutné pokaždé vytvářet či upravovat prostředí ramdisku ručně.
Ostatně stejný nástroj se volá i při instalaci nového jádra.
Konfigurační soubory a skripty spojené se sestavením ramdisku, se v systému vyskytují na třech místech:
- Adresáře v
/etc/initramfs-tools
jsou určeny pro uživatelskou konfiguraci - Do adresáře
/usr/share/initramfs-tools
umísťují své skripty instalační balíčky - A do adresáře
/var/lib/initramfs-tools
se ukládá kontrolní součet (realizovaný přes shasum ) ramdisku sestaveného pomocí initramfs-tools
kmod - se stará o načítání jaderných modulů v ramdisku
- načte shellový skript /hook-functions (používá funkce zde uvedené)
- zavolá funkci copy_exec, (která udělá co?)
- zkopíruje nástroje modprobe a rmmod
- se stará o include jaderných modulů.
udev -
Struktura konfiguračních adresářů pro sestavení ramdisku
/conf.d /hooks /scripts /init-bottom /init-top
initramfs.tools modules update-initramfs.tools
Od jádra verze >= 3.5 je modul nfs rozdělen na více modulů |
Reboot z prostředí ramdisku
echo b > /proc/sysrq-trigger
Monitoring
Lokální přesměrování konzolového výstupu
vmlinuz... console=ttyS0 ...
Síťové přesměrování konzolového výstupu
Pokud má jádro zakompilovaný modul netconsole, lze výstup přesměrovat po síti.
vmlinuz... netconsole=6665@[IP stanice]/[síťové zařízení],6666@[IP vzdálené stanice]/[MAC síťového rozhraní vzdálené stanice]
Na vzdálené stanici ale musí na příslušném portu naslouchat aplikace. Použít lze kupř. utilitu nc
nc -u -l -p 6666