next up previous contents index
Next: Prozeßordnung Up: Systemverwaltung Previous:    Der Anfang und

Subsections


Laufzeitmodule für den Kernel

  

Linux erlaubt das Hinzufügen modularer Gerätetreiber oder Funktionen in den laufenden Kernel. Ursprünglich wurde die Modulschnittstelle für den Linux-Kernel entwickelt, um den Programmierern bessere Möglichkeiten zum Testen neuer Gerätetreiber zu bieten. Es hat sich aber schnell gezeigt, daß die Modularisierung des Kernels viel mehr Vorteile bietet, deshalb wurden nach und nach fast alle Gerätetreiber und viele Kernelfunktionen -- wenigstens potentiell -- zu Modulen umgearbeitet.

Die Distributoren können mit einem vollständig modularisierten Kernel kleinere Installationssysteme herstellen, die zudem besser an das Zielsystem angepaßt sind als die überladenen generischen Kerneldateien auf den Bootdisketten der Vergangenheit.

Die Benutzer eines modularisierten Kernels profitieren von der Schlankheitskur des Betriebssystems. Alle Gerätetreiber, die nicht ständig in Benutzung sind, können als Module ausgelagert und nur bei Bedarf in den Speicher geladen werden.

Erzeugung und Installation von Kernelmodulen

Um aus einem normalen Treiber ein Modul zu machen, müssen zunächste die Sourcen des Treibers mit dem Compiler übersetzt werden. Zusätzlich ist in der Objektdatei zu jedem Treiber jeweils eine Funktion init_module und cleanup_module erforderlich, mit der das Modul sich selbst initialisieren und wieder auflösen kann.

Die Kernelsourcen enthalten für alle Treiber, deren Modularisierung sinnvoll ist, die entsprechenden Zusatzfunktionen und können deshalb sowohl als fester Kernelbestandteil als auch als Modul übersetzt werden. Das Kernelmakefile und das Konfigurationsscript unterstützen die Modularisierung und automatisieren die eigentliche Erzeugung der ladbaren Objektdateien. Die Systemverwalterin muß lediglich beim Konfigurieren eines neuen Kernels vor dem Übersetzen der Sourcen die gewünschten Module auswählen, danach die Module mit dem Kommando ``make modules'' compilieren und schließlich durch das Kommando ``make modules_install'' in das dafür vorgesehene Verzeichnis kopieren lassen.

Bei der Auswahl der Gerätetreiber, die als Modul übersetzt werden sollen, muß auf eventuelle Abhängigkeiten der Module untereinander geachtet werden. Die kritischen Abhängigkeiten werden vom Konfigurationsscript erkannt und nötigenfalls automatisch korrigiert. Beispielsweise ist es unmöglich, gleichzeitig den Dateisystemtyp msdos fest in den Kernel einzubauen und den Basistyp fat als Modul davon zu trennen.

Zusammenhang zwischen Modulen und Kernelversion

Die Kernelmodule sind nicht unabhängig von der Kernelversion, für die sie erzeugt wurden. Jedes Modul benutzt mehr oder weniger viele Funktionen und globale Variable, die vom laufenden Kernel exportiert werden und dem ``Kernellinker'' insmod als Symbole zum Linken zur Verfügung stehen. Diese exportierten Symbole bilden die Schnittstelle, an der die Module angekoppelt werden. Eine Liste der Symbole steht in der Pseudodatei /proc/ksyms und kann vom Systemprogramm ksyms  angezeigt werden.

Wenn eine der exportierten Funktionen in einer neuen Kernelversion verändert wird, müssen alle Module, die diese Funktion benutzen, neu übersetzt werden. Aus diesem Grund werden einfacherweise die Kernelmodule für jeden Patchlevel des Kernels neu übersetzt. Das Systemprogramm insmod  kann die Kernelversionsnummer, für die ein Modul übersetzt wurde, aus der Moduldatei lesen und verweigert normalerweise das Laden eines Moduls, wenn dessen Versionsnummer nicht mit der des laufenden Kernels übereinstimmt.

Dieses einfache Schema der Zuordnung von Modulen zur passenden Kernelversion ist in zweierlei Hinsicht unzureichend. Einerseits können im Zuge eigener Entwicklungsarbeit Veränderungen am Kernel und damit an der Modulschnittstelle stattfinden, ohne daß die Versionsnummer hochgezählt wird. Andererseits ist nicht jedes Modul vom Upgrade des Kernels auf den nächsten Patchlevel betroffen. Es ist durchaus möglich, daß ein Modul ohne Veränderung für viele Kernelversionen benutzt werden kann, wenn sich an den von diesem Modul benutzten Kernelfunktionen nichts ändert.

Um die Abhängigkeit der Module von der Versionsnummer des Kernels zu trennen und gleichzeitig die Verwendung älterer Module mit neuen Kernelversionen zu unterstützen, können Kernel und Module mit speziellen Versionsinformationen für die Modulschnittstelle ausgestattet werden. Um dieses Feature zu nutzen, muß der Kernel mit der Option CONFIG_MODVERSIONS übersetzt werden.

Die Namen aller exportierten Kernelsymbole werden dadurch beim Übersetzten des Kernels automatisch um eine Prüfsumme erweitert, die aus dem Programmtext für die entsprechende Funktion generiert wurde. Auf diese Weise kann sichergestellt werden, daß nur solche Module zum Kernel hinzugelinkt werden, die zur aktuellen Schnittstelle passen.

Aufbewahrung der Kernelmodule

Damit die Module für verschiedene Kernelversionen nicht durcheinander geraten, hat jede Kernelversion ihr eigenes Modulverzeichnis. Die Module werden bei der automatischen Installation durch das Kommando ``make modules_install'' in ein Unterverzeichnis von /lib/modules kopiert, dessen Name mit der Versionsnummer des Kernels übereinstimmt, für den sie übersetzt wurden. Wenn Sie beispielsweise die Module für Linux-2.0.18 übersetzt und installiert haben, befinden sich die Ojektdateien der Module für diese Kernelversion in dem Verzeichnis /lib/modules/2.0.18.

Zusätzlich werden die Module nach den Typen block, cdrom, fs, ipv4, misc, net und scsi geordnet und in entsprechenden Unterverzeichnissen aufbewahrt.

Alle Programme, die mit Kernelmodulen umgehen, suchen automatisch in dem zur laufenden Kernelversion gehörenden Modulverzeichnis nach dem Modul, das geladen werden soll.

Laden und Entfernen von Kernelmodulen

Zum Laden der Laufzeitmodule steht zunächst der Kernellinker insmod zur Verfügung, mit dem ein einzelnes Modul in den Kernel eingefügt werden kann. Wie der Linker des GCC versucht insmod, die unaufgelösten Symbole des Moduls mit den exportierten Symbolen des Kernels zu verbinden.

Wenn alle ``offenen Enden'' des Moduls erfolgreich mit dem Kernel verknüpft worden sind, veranlaßt der Linker die Initialisierung des Moduls durch die Modulfunktion init_module. Diese Funktion ist weitgehend mit der Initialisierungsfunktion identisch, die beim Booten eines fest installierten Treibers vom Kernel aufgerufen wird. Einige Treiber erlauben die Übergabe von Initialisierungsparametern, ähnlich der Bootparameter vom LILO Bootprompt.

[01] # insmod lp io=0x378 irq=7
[02] # insmod 3c503 io=0x280 xcvr=0
[03] # insmod msdos
fat_add_cluster: wrong version or undefined
fat_statfs: wrong version or undefined
fat_put_super: wrong version or undefined
...
Loading failed! The module symbols don't match your linux-2.0.18
[04] # _

Es ist möglich, daß ein Modul von einem anderen Modul abhängig ist. Das ist der Fall, wenn ein Modul Funktionen benutzt, die von einem anderen exportiert werden. In dem Beispiel werden vom Dateisystemtyp msdos Funktionen des Basistyps fat gebraucht. Um msdos als Modul laden zu können, muß deshalb das Modul für fat bereits geladen sein.

Diese Abhängigkeitsbeziehung von Modulen untereinander führt zu Ketten oder Modulstacks. Um einen solchen Stack mit insmod zu laden, müssen alle Module nacheinander in der richtigen Reihenfolge an den Kernel angehängt werden.

   Um das Laden von Modulstacks zu erleichtern, gibt es das Programmpaar depmod und modprobe. Mit depmod wird eine Datei erzeugt, in der die Abhängigkeit der Module aufgezeichnet ist. modprobe hat die gleiche Aufgabe wie insmod, es sorgt aber dafür, daß der Modulstack eines abhängigen Moduls komplett geladen wird. Dazu benutzt es die von depmod erzeugte Datei.

[01] # uname -sr
Linux 2.0.18
[02] # depmod -a
[03] # depmod -a 2.0.14
*** Unresolved symbols in module /lib/modules/2.0.14/fs/vfat.o
*** Unresolved symbols in module /lib/modules/2.0.14/misc/iBCS
*** Unresolved symbols in module /lib/modules/2.0.14/net/dummy.o
*** Unresolved symbols in module /lib/modules/2.0.14/net/ppp.o
[04] # modprobe msdos
[05] # modprobe -a -t fs \*
[06] #

Das zweite Kommando führt zur automatischen Prüfung der Abhängigkeiten aller Module, die im Modulverzeichnis für den laufenden Kernel (2.0.18) enthalten sind. Das dritte Kommando testet alle Module im Verzeichnis für die Kernelversion 2.0.14 auf Abhängigkeiten. Die Warnungen zeigen, daß einige dieser Module nicht zur laufenden Kernelversion passen. Die Abhängigkeit der Module untereinander wird trotzdem korrekt erkannt.

Das vierte Kommando zeigt den Vorteil von modprobe gegenüber insmod: beim Laden eines abhängigen Moduls wird automatisch der gesamte Modulstack geladen. Im fünften Kommando des Beispiels wird schließlich gezeigt, wie mit modprobe alle Module des Typs fs, also die Dateisysteme, automatisch geladen werden können. Ohne die Angabe eines Typs würde modprobe alle Module für den laufenden Kernel laden.

Die Konfigurationsdatei /etc/conf.modules

 

Das Programm modprobe kann durch die Konfigurationsdatei /etc/conf.modules auf eine besondere Systemumgebung und für spezielle Aufgaben eingestellt werden. Für alle möglichen Einstellungen benutzt das Programm eine lange Liste von Vorgaben, die mit der Kommandozeilenoption -c angezeigt wird. Die Liste läßt sich durch zusätzliche Einträge in der Konfigurationsdatei ergänzen, und die Vorgaben können durch eigene Definitionen ersetzt werden.

# Beispiel fuer /etc/conf.modules
keep
path[boot]=/usr/lib/modules

alias scsi_hostadapter aha1542

options lp io=0x378 irq=7

post-install lp tunelp /dev/lp1 -i 7

In den ersten Zeilen des Beispiels wird der Suchpfad erweitert, auf dem modprobe nach den angeforderten Kernelmodulen sucht. Der vorgegebene Suchpfad beginnt in /lib/modules/boot, geht dann über die Unterverzeichnisse des Modulverzeichnisses der laufenden Kernelversion und danach durch die Unterverzeichnisse von /lib/modules/default. Ohne das Schlüsselword keep wird der vorgegebene Suchpfad ersetzt und nicht, wie in diesem Fall, erweitert.

Die Definition von Aliasnamen hat für die direkte Verwendung mit modprobe nur kosmetische Bedeutung. In Kombination mit dem Kerneldämon kerneld wird über Aliasnamen die Auswahl eines bestimmten Moduls für eine allgemeinere Geräteklasse vorgenommen, wie in dem Beispiel für einen SCSI-Hostadapter gezeigt.

Beim Laden eines einzelnen Moduls kann modprobe, wie insmod, Symboldefinitionen als Argumente für die Modulinitialisierung übernehmen. Beim Laden eines Modulstacks oder einer Modulgruppe ist das nicht möglich, weil sich die Kommandozeilenargumente nicht den einzelnen Modulen zuordnen lassen. Stattdessen können in der Konfigurationsdatei für jedes Modul Optionen festgelegt werden, mit denen der Treiber beim Laden eingestellt wird.

Für aufwendigere Modulinitialisierungen besteht die Möglichkeit, vor und nach dem Laden des Moduls beliebige Kommandos ausführen zu lassen.

Initialisierungsparameter für modulare Gerätetreiber

    

Die Definition von Symbolen beim Laden eines Moduls durch insmod, beziehungsweise eines der Front-Ends modprobe oder kerneld, hat die Rolle des Bootparameters, der dem Kernel zur Initialisierung eines Gerätetreibers mit dem Bootprompt übergeben werden kann. Mit Hilfe dieser Symboldefinitionen können IO-Adressen, Interruptnummern und sonstige Angaben über die installierte Hardware an den modularen Treiber übergeben werden.

Leider werden zur Übergabe der Parameter in den beiden Anwendungsfällen ganz verschiedene Methoden benutzt.[*] Deshalb können die meisten modularen Treiber nicht einfach mit dem Bootparameter vom LILO Bootprompt initialisiert werden. Die Tabelle 5.3 zeigt die Symbole zur Initialisierung der wichtigsten modularen Treiber.


Gerät & Modul & Symbole
 Die Symbole zur Modulinitialisierung
Aztech CD aztcd azt_port=IO-Port
Sony CDU31a cdu31a cdu31a_port=IO-Portcdu31a_irq=IRQ sony_pas_init=FLAG
Phillips CM206 cm206 cm206=IO-Port,IRQ
GoldStar gscd gscd=IO-Port
Mitsumi MultiSession mcdx mcdx_drive_map=IO-Port,IRQ[,IO-Port,IRQ]
Optics Storage optcd optcd_port=IO-Port
CreativeLabs sbpcd sbpcd=IO-Port,Typ
Sanyo CDR-H94A sjcd sjcd_base=IO-Port
Sony CDU535 sonycd535 sony535_cd_base_io=IO-Port sony535_irq_used=IRQ
Ethernet ./net io=IO-Port irq=IRQ
NCR 53c7,8x 53c7,8xx base=Memory io_port=IO-Port irq=IRQ dma=DMA perm_options=Option
AM53/79C974 PCI AM53C974 host_scsi_id=ID target_scsi_id=ID max_rate=Rate max_offset=Offset
BusLogic BusLogic IO_Address=IO-Port
NCR 53c406a NCR53c406a port_base=IO-Port irq_level=IRQ fast_pio=XX dma_chan=XX bios_base=XX
Adaptec AHA152X aha152x aha152x=IO,IRQ,ID,Recon,Par...
Adaptec AHA1740 aha1740 slot=XX base=IO-Port irq_level=IRQ
Adaptec AHA-2940 aic7xxx aic7xxx_extended=1 aic7xxx_no_reset=1 aic7xxx_irq_trigger={-1,0,1}
Future Domain 16xx fdomain port_base=XX bios_base=XX interrupt_level=XX this_id=XX
Always IN2000 in2000 setup_strings=Liste

Sie können mit insmod alle exportierten statischen Variablen initialisieren. Arrays können durch eine kommaseparierte Liste von Werten belegt werden. Sie finden die in Frage kommenden Symbole durch eine Untersuchung der Moduldatei mit Hilfe des Tools nm. In der Tabelle erkennen Sie die Symbole am Buchstaben d.

Entfernen von Kernelmodulen

 

Einer der großen Vorteile von Kernelmodulen ist die Möglichkeit, sie wieder aus dem Kernel zu entfernen, sobald sie nicht mehr gebraucht werden. Der für diesen Zweck vorgesehene Antagonist von insmod ist das Kommando rmmod. Mit rmmod lassen sich auch ganze Modulstacks entfernen.

Bevor ein Modul aus dem Kernel herausgelöst und sein Speicherbereich freigegeben werden kann, muß es vollständig inaktiv sein. Es müssen alle Prozesse beendet sein, die das Modul benutzt haben. Auf den modularen Treiber einer Ethernetkarte dürfen auch keine Routen mehr laufen. Ist das Modul noch aktiv, während es mit rmmod entfernt werden soll, wird eine Fehlermeldung ausgegeben und das Modul unverändert im Kernel belassen.

Das Programm modprobe kann mit dem Schalter -r ebenfalls zum Löschen von Modulen eingesetzt werden. Es arbeitet dann wie rmmod.

Automatisches Laden und Entfernen von Modulen durch den Kerneldämon

   Im letzten Schritt zum perfekt modularisierten Kernel werden die Module bei Bedarf automatisch geladen und selbständig wieder entfernt, sobald sie nicht mehr benötigt werden. Diese Funktionalität wird durch das Zusammenspiel des Kernels mit einem speziellen Kerneldämon im Userspace realisiert. Zur Kommunikation mit dem kerneld benutzt der Kernel die Funktionen der Interprozeßkommunikation, IPC. Voraussetzungen zur Benutzung dieses Service sind dessen Aktivierung bei der Kernelkonfiguration vor dem Übersetzen der Sourcen (CONFIG_KERNELD) und ein im Hintergrund laufender Kerneldämon.

Bei jedem Versuch, auf ein unbekanntes Gerät, ein neues Binärformat, ein fremdes Netzwerkprotokoll oder ein bisher nicht unterstütztes Dateisystem zuzugreifen, übermittelt der Kernel eine Aufforderung zum Laden des fehlenden Moduls an den Dämon. Der Dämon gibt den Auftrag an das Programm modprobe weiter, das seinerseits versucht, das passende Modul zu finden und in den Kernel einzufügen.

Wenn das nötige Modul nicht geladen werden konnte, gibt der Kernel die übliche Fehlermeldung ``No such device'' aus, sonst arbeitet er ganz normal mit dem Modul weiter.

In der Aufforderung zum Laden eines Moduls benutzt der Kernel in der Regel nicht den Namen des Moduls, sondern eine Bezeichnung der fehlenden Funktion. Wenn zum Beispiel der Floppytreiber als Modul aus dem Kernel ausgelagert wurde und ein Prozeß versucht, auf ein Diskettenlaufwerk zuzugreifen, schickt der Kernel dem kerneld eine Anfrage der Form: request_module ('block-major-2'). Hinter block-major-2 verbirgt sich der Floppytreiber, das Blockdevice mit Hauptgerätenummer 2. Die Übersetzung in dieser Bezeichnung in den Namen des Kernelmoduls wird von modprobe durch einen Aliasnamen vorgenommen. In der Liste von Vorgaben, die in modprobe ohne weiteres Zutun enthalten ist, sind die Aliasnamen für alle gängigen Kernelmodule enthalten.

Es gibt jedoch einige Module, die nicht anhand der vom Kernel abgegebenen Anfrage identifiziert werden können. Wenn zum Beispiel auf ein SCSI-Bandlaufwerk zugegriffen werden soll und außer dem Treiber für das Bandgerät auch der Treiber für den SCSI-Hostadapter als Modul geladen werden muß, fordert der Kernel nur ein Modul mit der Bezeichnung scsi_hostadapter. Der Kernel hat keine Möglichkeit festzustellen, welcher Hostadapter in den Rechner eingebaut ist.

In diesem Fall muß das passende Modul durch eine entsprechende Aliasdefinition in der Datei /etc/conf.modules identifiziert werden.

Kernelmodule, die mit dem kerneld geladen wurden, sind bei einem Listing der aktiven Module durch lsmod mit dem Zusatz (autoclean) gekennzeichnet. Das bedeutet, daß diese Module automatisch entfernt werden, wenn sie länger als eine Minute nicht mehr benutzt werden.    


next up previous contents index
Next: Prozeßordnung Up: Systemverwaltung Previous:    Der Anfang und

Das Linux Anwenderhandbuch
(C) 1997 LunetIX