Kategória: Debian Linux

Zmenené: 26. jún 2010

Hrátky s jadrom

Väčšina súčasných distribúcií používa pre zavedenie systému jadro rozdelené na dve časti samotné jadro a inicializačný RAM disk. Pre bežného používateľa často veci zaradené do kategórie nedotýkať sa. Avšak nie je to až taká mágia, ako sa na prvý pohľad môže zdať a v tomto článku s pokúsim ukázať, ako si možno tieto dve veci prispôsobiť na vlastný obraz.

Potrebujem to?

Krátka odpoveď znie nie. Dlhšia odpoveď znie možno a úplná odpoveď znie závisí na tom, čo od svojho systému očakávate. Manipulácii s inštaláciou jadra sa nevyhnete v situácii, keď niečo nefunguje.

Niekedy po aktualizácii jadra môžu nastať napríklad problémy, a to najmä v prípade, keď používate ovládače (moduly jadra), ktoré nie sú súčasťou distribúcie. V takom prípade nie je pri aktualizácii jadra automaticky vybudovaný nový modul jadra a po nadšenom reštarte do nového jadra sa začínajú diať veci… Iný prípad je, keď máte hardvér, ktorého ovládače existujú vo viacerých verziách, či vyžadujú špeciálne parametre. No a, v neposlednom prípade, sa do takýchto experimentov pustíte, keď si chcete optimalizovať beh systému alebo prosto len tak, aby ste objavili niečo nové.

Jadro a moduly

Začnem trochu kontroverznou témou, za ktorú považujem moduly jadra. Existujú viac-menej dve hraničné skupiny používateľov. Jedni ich považujú za super vec, druhí zase za pohromu. V podstate sa jedná najmä o moduly ovládačov hardvéru, či súborových systémov a podobne. Tieto veci môžu byť zabudované priamo do jadra a vtedy sú vždy načítané do pamäti spolu s jadrom. Druhý spôsob je ich kompilácia ako modulov jadra a potom bývajú načítané až keď ich je naozaj treba alebo ak je to nastavené. To, či bude nejaká časť vybudovaná ako modul alebo zakompilovaná priamo do jadra, sa nastavuje pri konfigurácii kompilácie jadra.

Upozornenie

Nebudem sa tu zaoberať rekompiláciou jadra, a teda nebudem popisovať ako meniť, či tá ktorá časť je súčasťou jadra alebo je to modul. Naproti tomu sa uspokojím s tým, ako vývojari jadra rozhodli a zhrniem čo sa s tým dá robiť, a to najmä ohľadom ovládačov hardvéru.

Práca s modulmi

Väčšinou je práca s modulmi ovládačov pre používateľa transparentná, čiže používateľ ani nevie, čo a kedy sa načíta (o ich načítanie sa stará udev). Niekedy je však potrebné príslušný modul načítať ručne, napríklad keď hľadáte, ktorý je ten správny. V takom prípade poslúžia nástroje modprobe a insmod. Príkaz comm;modprobe` slúži na načítanie (ale aj na uvoľnenie) modulu pomocou jeho mena. Príslušné moduly hľadá v adresári /lib/modules/$(uname -r) a meno modulu stačí zadať bez prípony, napríklad načítanie proprietárneho ovládača grafických kariet nVidia zaistí príkaz:

modprobe nvidia

Rovnaký nástroj možno použiť aj na uvoľnenie načítaného modulu:

modprobe -r nvidia

Správanie modprobe je možné modifikovať pomocou mnohých parametrov príkazového riadku (viac v man modprobe) a spolu s menom modulu je možné zadať aj parametre modulu.

Ako som spomenul vyššie, nástroj modprobe hľadá zadaný modul v adresári modulov jadra, ak ste si skompilovali modul sami a ešte nie je nainštalovaný v tomto adresári, poslúži nástroj insmod, ktorý načíta modul jadra zadaný menom súboru (aj s príponou), a tak môže byť tento modul uložený na ľubovoľnom mieste:

insmod /usr/src/moj_super_modul.so

Nástroj insmod neposkytuje žiadne parametre príkazového riadku, ale i pomocou tohoto nástroja možno zadať parametre modulu.

Spomínal som parameter -r príkazu modprobe;, ktorý slúži na uvoľnenie modulu z jadra. Aj odstraňovanie modulov má svoju nízkoúrovňovú verziu, a to :command:`rmmod:

rmmod nvidia

Ak chcete preskúmať, aké moduly má vaše jadro práve načítané, poslúži príkaz lsmod, ktorý vypíše zoznam všetkých načítaných modulov, vrátane niekoľkých informácií o nich (vlastne len čitateľnejšie interpretuje obsah /proc/modules):

lsmod
Module                  Size  Used by
rfcomm                 29581  0
l2cap                  24736  6 bnep,rfcomm
bluetooth              41827  6 sco,bnep,rfcomm,l2cap
rfkill                 13044  2 bluetooth

Tento výpis je samozrejme skrátený, ale vidno na ňom, že výpis je rozdelený do troch (štyroch) stĺpcov. V prvom je meno modulu, nasledované jeho veľkosťou. Na konci sú informácie o závislostiach, najprv je počet modulov, ktoré ho využívajú, nasledovaný zoznamom modulov, ktoré sám používa (nemusí na nich nutne aj závisieť).

Popis príkazov pre prácu s modulmi jadra uzatvorím programom depmod, ktorý slúži na generovanie súboru modules.dep (súbor s popisom závislostí modulov) a súboru map. Tento príkaz možno spustiť s menom súboru modulu, čím je preskúmaná závislosť len tohoto modulu, ale asi najčastejšie použitie bude s voľbou -a, ktorá sa postará o prejdenie všetkých modulov v adresári /lib/modules/$(uname -r) (vlastne pomocou týchto závislostí dokáže modprobe nájsť správny súbor):

depmod -a

Príkaz depmod je vhodné spustiť po každej manuálnej inštalácii nejakého modulu.

Zakazovanie modulov

Niekedy je snaha vývojárov distribúcie márna a sada modulov nevyhovuje vášmu hardvérovému vybaveniu, napríklad preto, že na niektorý hardvér existuje viacero ovládačov a ako natruc sa načíta práve ten, ktorý sa nemá alebo ktorý nechcete. Túto situáciu je možné riešiť pomocou zakázania načítania modulu direktívou blacklist, nasledovanou menom modulu. Túto direktívu môžete nájsť aj v súbore /etc/modprobe.d/blacklist.conf. Tento súbor je však súčasťou balíka udev a jeho zmeny môžu byť stratené pri aktualizácii balíka.

Vhodnejší spôsob je vytvoriť si v tomto adresári nový súbor, ktorý môžete nazvať ako chcete, ale musí mať príponu .conf, napríklad pre zakázanie načítania modulu nouveau bude tento súbor obsahovať:

blacklist nouveau

Takýmto spôsobom zakázané moduly nebudú zahrnuté ani do initrd.

Parametre modulov

Niektorým modulom je potrebné definovať parametre, ktoré pri jeho načítaní ovplyvnia jeho správanie. Ako som spomínal vyššie, tieto parametre možno zadať pri načítaní modulu pomocou programov modprobe, či insmod. Lenže pre automatické načítanie modulov nám takáto možnosť nepostačí, ale rovnako ako pri zakazovaní modulov, aj pre tento účel si môžeme vytvoriť súbor v adresári /etc/modprobe.d/ (tiež s príponou .conf), tentokrát však s direktívou options, nasledovanou menom modulu a príslušnými voľbami.

Aké sú parametre modulov? Toto je síce ľahká a logická otázka, ale nie vždy ľahko zopovedateľná. Jednou z možností, je nájsť príslušné voľby na internete, kde sa odpovede povaľujú na rôznych fórach, alebo preskúmať zdrojový kód modulu (často obsahuje súbor s popisom volieb). Inou možnosťou je použiť program modinfo, ktorý zobrazuje rôzne informácie o súbore modulu, vrátane možných volieb:

modinfo nouveau
filename: /lib/modules/2.6.32-5-amd64/kernel/drivers/gpu/drm/nouveau/nouveau.ko
license: GPL and additional rights
description: nVidia Riva/TNT/GeForce
author: Stephane Marchesin
alias: pci:v000012D2d*sv*sd*bc03sc*i*
alias: pci:v000010DEd*sv*sd*bc03sc*i*
depends: drm,drm_kms_helper,ttm,i2c-core,button,i2c-algo-bit
vermagic: 2.6.32-5-amd64 SMP mod_unload modversions
parm: ctxfw:Use external firmware blob for grctx init (NV40) (int)
parm: modeset:Enable kernel modesetting (int)
parm: vbios:Override default VBIOS location (charp)
parm: vram_pushbuf:Force DMA push buffers to be in VRAM (int)
parm: vram_notify:Force DMA notifiers to be in VRAM (int)
parm: duallink:Allow dual-link TMDS (>=GeForce 8) (int)
parm: uscript_lvds:LVDS output script table ID (>=GeForce 8) (int)
parm: uscript_tmds:TMDS output script table ID (>=GeForce 8) (int)
parm: ignorelid:Ignore ACPI lid status (int)
parm: noaccel:int
parm: noagp:Disable AGP (int)
parm: nofbaccel:int
parm: tv_norm:Default TV norm.
           Supported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,
           hd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.
           Default: PAL
           *NOTE* Ignored for cards with external TV encoders. (charp)
parm: reg_debug:Register access debug bitmask:
           0x1 mc, 0x2 video, 0x4 fb, 0x8 extdev,
           0x10 crtc, 0x20 ramdac, 0x40 vgacrtc, 0x80 rmvio,
           0x100 vgaattr, 0x200 EVO (G80+). (int)

Nástroj modinfo je určený skôr pre skúsených používateľov. V lepšom prípade popis volieb obsahuje aj zoznam možných hodnôt, ale nie je to pravidlo. Našťastie som tieto voľby potreboval vlastne len raz, a to na nastavenie typu zvukovej karty (teda počtu výstupov).

Automatická aktualizácia modulov

Ako možno vyplynulo z predchádzajúceho textu, hoci som to výslovne nespomenul, je, že modul musí byť skompilovaný pre príslušnú verziu jadra. Ak používate len distribučné verzie modulov, nebýva to problém, pretože vývojári Debianu odvádzajú kvalitnú prácu a spolu s novou verziou jadra poskytujú aj nové verzie modulov. Lenže sloboda Linuxu spočíva v tom, že túto prácu vývojárov distribúcie (nie len Debianu) môžete využiť, ale nie ste na ňu odkázaní a môžete do jadra doplniť prakticky čokoľvek. Lenže, vždy po aktualizácii jadra je potrebné túto kompiláciu vykonať znova, čo môže byť nie len nepríjemné, ale často to môže aj poriadne skomplikovať život (napríklad taký ovládač sieťovej karty, ktorý môže spôsobiť dočasnú nefunkčnosť internetu a tým nemožnosť napríklad stiahnuť zdrojový kód modulu).

Jednou z možností ako túto prácu zautomatizovať je použiť možnosť automatického spúšťania skriptov pri inštalácii či odinštalovaní príslušnej verzie jadra. Tieto skripty je možné umiestniť do adresárov /etc/kernel/postinst.d na automatickú inštaláciu a /etc/kernel/postrm.d na automatické odinštalovanie. Ja tieto skripty využívam pre automatickú prácu s modulmi pre VirtualBox a grafickú kartu nVidia. Skriptom v týchto adresároch sú posielané i parametre, prvým parametrom je verzia jadra v tvare, aký vráti príkaz uname -r a druhým je cesta k jadru.

Nebudem v tomto článku popisovať konkrétny skript, ale poskytnem len príklad ukážkového skriptu, ktorý vypíše informácie niektoré informácie do /var/log/syslog:

#!/bin/bash
# Jednoduchý ukážkový skript /etc/kernel/postinst.d/test
# Jeho jedinou úlohou je vypísať verziu inštalovaného jadra do syslog
VERZIA="$1"

# verzia jadra je vyžadovaná
[ -z "${VERZIA}" ] && exit 0

logger -s -t "driver info" "Spustený poinštalačný hook pre jadro $VERZIA" >&2

exit 0

Ak chcete funkčnosť tohoto súboru vyskúšať, nemusíte inštalovať nejakú inú verziu jadra (ako je v mnohých návodoch), plne stačí spustiť rekonfiguráciu aktuálneho jadra:

dpkg-reconfigure linux-image-$(uname -r)

Pozor na kombináciu vkladania modulov do initrd, pretože tieto skripty sa spúšťajú až po generovaní initrd. Ak teda chcete (potrebujete) do initrd vložiť modul, ktorý je generovaný takýmto skriptom, je poterbné pridať i opätovnú generáciu initrd.

Inicializačný RAMdisk

Hoci je stále možné zakompilovať všetko do jediného súboru jadra, v súčasných linuxových distribúciách sa s tým môžete stretnúť len vo výnimočných prípadoch (väčšinou distribúcie na špeciálne účely) a je použitý inicializačný RAM disk. Tento inicializačný RAMdisk (initrd) sa načíta do pamäte ihneď po načítaná jadra a slúži ako počiatočný inicializačný koreňový adresár. Obsahuje moduly, ktoré sú potrebné pri štarte jadra, ale najmä pre pripojenie reálneho koreňového súborového systému.

V Debiane sa ním potrebujete zaoberať len výnimočne, pretože o všetko sa transparentne (pre používateľa) postará inštalačný systém jadra a pri inštalácii alebo aktualizácii jadra, či niektorých modulov automaticky spustí generovanie alebo aktualizáciu initrd. Na manipuláciu s týmto initrd slúži balík initramfs-tools a pri jeho inštalácii(väčšinou už pri inštalácii systému) sa pýta na to, či vložiť do initrd všetky moduly alebo len tie potrebné. Teraz ruku na srdce, keď ste na túto otázku odpovedali, vedeli ste ktorá voľba je správna?

Nech už ste odpovedali tak, či onak, je to samozrejme možné zmeniť, a to v súbore /etc/initramfs-tools/initramfs.conf. Tento súbor obsahuje viacero konfiguračných volieb, ale asi najdôležitejšia je voľba MODULES. Môže nadobúdať jednu zo štyroch hodnôt:

  • most – pridá moduly väčšiny súborových systémov a všetkých ovládačov pevných diskov
  • dep – pridá len potrebné moduly
  • netboot – pridá sieťové moduly a vynechá moduly pevných diskov
  • list – pridá len moduly zo zoznamu

Voľba most je vhodná na univerzálny systém, kde sa môže meniť konfigurácia diskov a poskytuje istotu, že sa pri štarte spustia všetky potrebné moduly. Naproti tomu voľba dep poslúži na ustálený systém, ale prináša riziko, že systém nemusí naštartovať (pravdepodobnosť je veľmi nízka, ale je). Bežný stolný počítač bude spoľahlivo fungovať s obomi týmito voľbami, a ak vám nezáleží na veľkosti súboru (závisí na tom doba načítania a dekomprimácie), nemusíte ich vôbec riešiť. Voľba netboot poslúži pri štarte po sieti a voľba list je vhodná pre expertov.

Napriek tomu, že initramfs-tools spoľahlivo vloží do initrd potrebné moduly, môžu nastať situácie, v ktorých je potrebné ručne pridať niektorý modul. Pre tento účel je určený súbor /etc/initramfs-tools/modules, do ktorého stačí pridať zoznam dodatočných (alebo všetkých pri voľbe list) modulov. A samozrejme vygenerovať nový initrd:

update-initramfs -u

Voľba -u udáva aktualizáciu súboru intrd (/boot/initrd.img-[verzia]-]architektúra]), ak chcete vygenerovať nový initrd, použite voľbu -c. V oboch prípadoch sa vo východzom nastavení jedná o initrd pre aktuálne bežiace jadro. Ak máte v systéme viacero jadier, a chcete aby boli aktualizované initrd pre všetky jadrá, musíte zmeniť voľbu pre update-initramfs v súbore /etc/initramfs-tools/update-initramfs.conf. Táto voľba môže nadobúdať jednu z troch hodnôt:

  • yes – pre povolenie aktualizácie initrd pri aktualizácii jadra
  • no – pre zakázanie aktualizácie initrd
  • all – pre povolenie aktualizácie initrd, ale pre všetky nainštalované jadrá

Istý čas som mal dve jadrá a každom mi fungoval iný kus hardvéru (ktorý nefungoval v tom druhom), vtedy som automatickú aktualizáciu oboch initrd ocenil.

Súčasný súbor initrd v Debiane je komprimovaný archív cpio. Typ komprimácie udáva voľba COMPRESS v súbore initramfs.conf (gzip). Túto informáciu oceníte najmä v prípade, že sa pustíte do experimentovania s initrd a budete si chcieť pozrieť, čo všetko obsahuje, pretože na základe vedomosti o štruktúre súboru initrd si ho možno ľahko rozbaliť a následne preskúmať:

mkdir /tmp/initrd
cd /tmp/initrd
zcat /boot/initrd.img-[verzia]-[architektúra] | cpio -i

Staršie verzia jadra používali komprimovaný alebo nekomprimovaný obraz súborového systému, ktorý bolo potrebné pripojiť pomocou zariadenia loop.

Záver

Možno som to mal napísať na začiatku, ale možno vám to vôbec nechýbalo, ale pre úplnosť ešte uvediem, predvolený adresár so súbormi jadra a initrd je adresár /boot. V tomto adresári sú súbory jadra pomenované vmlinuz-* a súbory initrd, pomenované initrd.img-*. Oba obsahujú za pomlčkou číslo verzie a architektúru, napríklad:

initrd.img-2.6.32-5-amd64
vmlinuz-2.6.32-5-amd64

Samozrejme, toto pomenovanie platí len pre distribučné jadrá, ak používate vlastné, môže sa volať úplne inak a byť uložené úplne inde.