Übersicht
Stichwortsuche
History
Versionen
Kategorien
Alle Artikel
SuSE Linux: Versionen ab 6.3
Sobald der Linux-Kernel geladen ist und das Root-Dateisystem ("/") gemountet hat, können Programme ausgeführt und weitere Kernel-Module geladen werden, um zusätzliche Funktionalitäten bereitzustellen.
Um aber das Root-Dateisystem überhaupt mounten zu können, müssen verschiedene Bedigungen erfüllt sein: Der Kernel benötigt die entsprechenden Treiber, um das Gerät ansprechen zu können, auf dem das Root-Dateisystem liegt (insbesondere SCSI-Treiber). Weiter muss der Kernel den Code enthalten, der benötigt wird, um das Dateisystem lesen zu können (ext2, reiserfs, romfs usw.). Weiterhin ist es denkbar, dass bereits das Root-Dateisystem verschlüsselt ist; zum Mounten ist in diesem Fall die Eingabe des Schlüssels/Passworts erforderlich.
Betrachtet man nur einmal das Problem der SCSI-Treiber, so sind verschiedene Lösungsansätze denkbar: Der Kernel kann alle denkbaren Treiber enthalten. Problematisch, da sich verschiedene Treiber "beissen" können; ausserdem wird der Kernel dadurch sehr gross. Eine andere Möglichkeit besteht darin, verschiedene Kernel zur Verfügung zu stellen, die jeweils nur einen oder sehr wenige SCSI-Treiber enthalten. Auch dieser Weg ist problematisch, da er eine sehr grosse Zahl unterschiedlicher Kernel notwendig macht. Ein Problem, das durch verschieden optimierte Kernel (Pentium-Optimierung, SMP) noch weiter verschärft wird.
Der Ansatz, den SCSI-Treiber als Modul zu laden, führt zur generellen Problematik, der durch das Konzept der initial ramdisk begegnet wird: Das Schaffen einer Möglichkeit, Userspace-Programme bereits vor dem Mounten des Root-Dateisystems ausführen zu können.
Die initial ramdisk (auch initdisk oder initrd genannt) löst genau diese
oben beschriebenen Probleme. Der Linux-Kernel bietet die Möglichkeit, ein
(kleines) Dateisystem in eine Ramdisk laden zu lassen, und darin Programme
ausführen zu lassen, bevor das eigentliche Root-Dateisystem gemountet
wird. Das Laden der initrd wird dabei vom Bootloader (LILO
, loadlin
usw.)
übernommen; all diese Bootloader benötigen lediglich BIOS-Routinen, um
Daten vom Bootmedium zu laden. Wenn der Bootloader den Kernel laden kann,
dann kann er auch die initial ramdisk laden. Spezielle Treiber sind somit
nicht erforderlich.
Der Bootloader lädt den Kernel und die initrd in den Speicher und startet den Kernel, wobei der Bootloader dem Kernel mitteilt, dass eine initrd vorhanden ist und wo im Speicher diese liegt.
War die initrd komprimiert (was typischerweise der Fall ist), so
dekomprimiert der Kernel die initrd und mountet sie als temporäres
Root-Dateisystem. Hierauf wird in der initrd ein Programm mit dem Namen
linuxrc
gestartet. Dieses Programm kann nun all die Sachen tun, die
erforderlich sind, um das richtige Root-Dateisystem mounten zu können.
Sobald linuxrc
terminiert, wird die (temporäre) initrd wieder unmounted
und der Bootvorgang wird wie gewohnt mit dem Mounten des richtigen
Root-Dateisystems fortgeführt. Das Mounten der initrd und das Ausführen
von linuxrc
kann somit als ein kurzes Intermezzo während eines normalen
Bootvorgangs betrachtet werden.
Kann die initrd nicht unmountet werden (was i.a. als Fehler angesehen werden sollte), so versucht der Kernel die initrd auf das Verzeichnis /initrd um-zumounten. Ist auch der Mountpunkt /initrd nicht vorhanden, so resultiert eine Fehlermeldung. Das System ist in einem solchen Fall voll funktionsfähig, jedoch kann der durch die initrd belegte Speicher nie freigegeben werden und steht somit nicht mehr zur Verfügung.
Für das Programm linuxrc
in der initrd gibt es lediglich die folgenden
Anforderungen: Es muss den speziellen Namen linuxrc
tragen und es muss
im Root-Verzeichnis der initrd liegen. Abgesehen davon muss es lediglich
vom Kernel ausgeführt werden können. Das bedeutet, dass linuxrc
durchaus
dynamisch gelinkt sein darf; in diesem Fall müssen natürlich die shared
libraries wie gewohnt vollständig unter /lib in der initrd verfügbar
sein. Weiter darf linuxrc
auch ein shell script sein; in diesem Fall muss
natürlich eine shell in /bin existieren. Kurz gesagt, muss die initrd ein
minimales Linux-System enthalten, das die Ausführung des Programmes
linuxrc
erlaubt. Linuxrc wird mit root-Rechten ausgeführt.
Sobald linuxrc
terminiert, wird die initrd unmountet und verworfen, der
Bootvorgang geht normal weiter und der Kernel mountet das wirkliche
Root-Dateisystem. Was als Root-Dateisystem gemountet werden soll, kann
durch linuxrc
beeinflusst werden. Dazu muss linuxrc
lediglich das
/proc-Dateisystem mounten und den Wert des echten Root-Dateisystems in
numerischer Form nach /proc/sys/kernel/real-root-dev schreiben.
Die meisten Bootloader (vor allem LILO
, loadlin
und syslinux
)
können mit initrd umgehen. Die einzelnen Bootloader werden wie folgt angewiesen, eine
initrd zu verwenden:
Eintrag der folgenden Zeile in /etc/lilo.conf
initrd=/boot/initrd
Die Datei "/boot/initrd" ist die initial ramdisk. Sie kann (muss aber nicht) komprimiert sein.
Aufruf mittels:
loadlininitrd=C:\linux\initrd
Eintrag der folgenden Zeile in syslinux.cfg
append initrd=initrd
Die initrd wird bereits seit geraumer Zeit für die Installation
verwendet: Dabei kann der Anwender in linuxrc
Module laden und die für
eine Installation notwendigen Eingaben (wie vor allem Quellmedium) machen.
Linuxrc startet dann YaST
, das die Installation durchführt. Hat YaST
seine Arbeit getan, teilt es linuxrc
mit, wo das Root-Dateisystem des
frisch installierten Systems liegt. Linuxrc schreibt diesen Wert nach
/proc
, beendet sich, und der Kernel bootet in das frisch installierte
System weiter.
Bei einer Installation von SuSE Linux bootet man somit von Anfang an quasi das System, das gerade erst installiert wird. Ein echter Reboot nach der Installation erfolgt nur, wenn der gerade laufende Kernel nicht zu den Modulen passt, die im System installiert wurden. Da SuSE Linux derzeit bei der Installation einen Kernel für Uni-Prozessor-Systeme verwendet, geschieht dies derzeit nur dann, wenn im System ein SMP-Kernel mitsamt entsprechenden Modulen installiert wurde. Um alle Module verwenden zu können, muss deshalb der neu im System installierte SMP-Kernel gebootet werden.
In der Vergangenheit hat YaST
mehr als 40 Kernel für die Installation im
System angeboten, wobei sich die Kernel im wesentlichen dadurch
unterschieden hatten, dass jeder Kernel einen bestimmten SCSI-Treiber
enthielt. Dies war nötig, um nach dem Booten das Root-Dateisystem mounten
zu können. Weitere Treiber konnten dann als Modul nachgeladen werden.
Da inzwischen aber auch optimierte Kernel zur Verfügung gestellt werden, ist dieses Konzept nicht mehr tragbar (es wären inzwischen weit über 100 Kernel-Images nötig).
Daher wird nun auch für das normale Starten des Systems eine initrd
verwendet. Die Funktionsweise ist analog wie bei einer Installation. Das
hier eingesetzte linuxrc
ist jedoch einfach nur ein shell script, das
lediglich die Aufgabe hat, einige vorgegebene Module zu laden.
Typischerweise handelt es sich nur um ein einziges Modul, nämlich
denjenigen SCSI-Treiber, der benötigt wird, um auf das Root-Dateisystem
zugreifen zu können.
Das Erstellen einer initrd erfolgt mittels des Scripts mk_initrd
. Die zu
ladenden Module werden bei SuSE Linux durch die Variable INITRD_MODULES
in /etc/rc.config festgelegt. Nach einer Installation wird diese Variable
automatisch durch die richtigen Werte vorbelegt (das Installations-linuxrc
weiss ja, welche Module geladen wurden). Dabei ist zu erwähnen, dass die
Module in genau der Reihenfolge geladen werden, in der sie in
INITRD_MODULES
auftauchen. Das ist besonders wichtig, wenn mehrere
SCSI-Treiber verwendet werden, da sich ansonsten die Benennung der Platten
ändern würde. Strenggenommen würde es reichen, nur denjenigen
SCSI-Treiber laden zu lassen, der für den Zugriff auf das
Root-Dateisystem benötigt wird. Da das automatische Nachladen
zusätzlicher SCSI-Treiber jedoch problematisch ist (wie sollte es
getriggert werden, wenn auch am zweiten SCSI-Adapter Platten hängen),
laden wir alle bei der Installation verwendeten SCSI-Treiber mittels der
initrd.
Das aktuelle mk_initrd prüft, ob für den Zugriff auf das Root-Dateisystem überhaupt ein SCSI-Treiber benötigt wird. Ruft man mk_initrd auf einem System auf, bei dem / auf EIDE-Platten liegt, erstellt es keine initrd, da diese nicht nötig ist, weil die bei SuSE verwendeten Kernel bereits die EIDE-Treiber enthalten. Da inzwischen immer mehr spezielle EIDE-Controller auf den Markt kommen, wird es aber voraussichtlich für die Zukunft nötig werden, auch in diesen Fällen eine initrd für das Booten des installierten Systems zu verwenden.
Wichtig: Da das Laden der initrd durch den Bootloader genauso abläuft wie
das Laden des Kernels selbst (LILO
vermerkt in seiner map-Datei die Lage
der Dateien), muss nach jeder Aenderung der initrd LILO
neu installiert
werden! Nach einem mk_initrd
ist somit immer auch ein lilo
nötig!
Uebersetzt man sich selbst einen Kernel, so kann es zu folgendem häufigen Problem kommen: Aus Gewohnheit wird der SCSI-Treiber fest in den Kernel gelinkt, die bestehende initrd bleibt aber unverändert. Beim Booten geschieht nun folgendes: Der Kernel enthält bereits den SCSI-Treiber, die Hardware wird erkannt. Die initrd versucht nun jedoch, den Treiber nochmals als Modul zu laden; dies führt bei einigen SCSI-Treibern (insbesondere beim aic7xxx) zum Stillstand des Systems. Strenggenommen handelt es sich um einen Kernelfehler (ein bereits vorhandener Treiber darf nicht ein zweites Mal als Modul geladen werden können), das Problem ist aber bereits in anderem Zusammenhang bekannt (serieller Treiber).
Es gibt mehrere Lösungen für das Problem: Entweder den Treiber als Modul
konfigurieren (dann wird er korrekt in der initrd geladen), oder aber den
Eintrag für die initrd aus /etc/lilo.conf entfernen. Aequivalent zur
letzteren Lösung ist es, den Treiber aus INITRD_MODULES
zu entfernen und
mk_initrd
aufzurufen, das dann feststellt, dass keine initrd benötigt
wird.
Ist für das Laden eines bestimmten Modules die Angabe von Parametern notwendig, dann gehen diese nach der Installation verloren; sie werden nicht in die für das Booten des Systems verwendete initrd eingetragen. Glücklicherweise gibt es nur sehr wenige SCSI-Treiber, die zwingend die Angabe von Parametern erfordern. Wer auf das Problem stösst, muss sein System mit der Installations-Bootdiskette booten und sich einen Kernel bauen, der den SCSI-Treiber enthält.
Das Problem ist inzwischen behoben, bei SuSE 6.4 werden etwaige Modulparameter auch beim Starten des Systems in der initrd verwendet.
Wurden bei der Installation Netzwerktreiber geladen, so werden auch diese
in INITRD_MODULES
eingetragen und somit in der initrd beim Booten des
Systems geladen. Während dies nicht per se ein Fehler ist, kann es doch
in einigen Fällen zu Problemen kommen:
1. NE2000 kompatible Karten: Der Treiber für diese Karten benötigt ein
zusätzliches Modul (8390.o). Modul-Abhängigkeiten werden derzeit jedoch
nicht beachtet, das Laden des Modules ne.o schlägt somit fehl. Da im
späteren Verlauf beim Konfigurieren des Netzwerks das Laden des
Netzwerktreibers von kerneld getriggert wird (und diesmal werden durch
Verwendung von "modprobe" auch Abhängigkeiten berücksichtigt), handelt
es sich um ein rein kosmetisches Problem: Das erste Laden scheitert mit
einer Fehlermeldung, das zweite Laden ist jedoch erfolgreich, da das Alias
eth0=ne
in /etc/modules.conf
korrekt gesetzt ist.
2. Erzwingen bestimmter Einstellungen: Soll eine Netzwerkkarte in den full-duplex mode gezwungen werden oder ein bestimmter media type verwendet werden (z.B. beim tulip-Treiber durch den Parameter options=xxx), so schlägt dies fehl, da - wie oben beschrieben - die bei der Installation verwendeten Parameter nicht mehr verwendet werden.
Auch diese Probleme sind mittlerweile gelöst. Zum einen werden künftig
Modulparameter korrekt weiterverwendet, zum anderen lässt das
Installations-linuxrc nunmehr nur noch SCSI-Treiber in INITRD_MODULES
eintragen.
/usr/src/linux/Documentation/ramdisk.txt
/usr/src/linux/Documentation/initrd.txt
Siehe auch:
Stichwörter: BOOT, INITRD, RAMDISK, VFS, SCSI, LILO, LOADLIN
Übersicht
Stichwortsuche
History
Versionen
Kategorien
Alle Artikel