Kernel (de) Kernel (it) Books Shell Sed/awk RAM/swap P35

Konfigurieren, Compilieren und Installieren eines Kernels 2.6 unter openSUSE Linux

Autor und Copyright: Dr. Thomas Hertweck
Ergänzungen und Korrekturen von Jan Engelhardt
Version: 1.01; Stand: 10. Januar 2008

Inhaltsverzeichnis

  1. Zum Umgang mit diesem Dokument
  2. Vorwort
  3. Die Kernel-Quellen
  4. Auspacken der Kernel-Quellen
  5. Patchen der Kernel-Quellen
  6. Klonen einer existierenden Kernelkonfiguration
  7. Anpassen des Kernel-Releases
  8. Durchführen der Kernel-Konfiguration
  9. Compilieren des Kernels
  10. Installation des Kernels
  11. Anpassen der Bootloader-Konfigurationsdatei
  12. Probleme beim Booten des neuen Kernels
  13. Sonstiges
  14. Installieren mehrerer Kernel per RPM
  15. Installieren externer Kernel-Module
  16. Der Boot-Prozess
  17. Der Linux-Kernel: wie alles begann
  18. Links
  19. Danksagung
  20. Disclaimer

Zum Umgang mit diesem Dokument

Die neuste Version dieses Dokuments kann stets unter http://www.thomashertweck.de/kernel26.html gefunden werden. Der Einfachheit wegen wird in diesem Howto i.d.R. nur von SUSE, nicht von Novell oder dem openSUSE-Projekt die Rede sein. Dieses Howto ist in keinster Weise direkt mit Novell/SUSE verknüpft, daher sollte Novell/SUSE beim Auftauchen irgendwelcher Probleme mit diesem Howto auch nicht über das Feedback-Formular belästigt werden. Alle Trademarks, die hier erwähnt werden, gehören ihrem jeweiligen Besitzer.

Beim Konfigurieren, Compilieren und Installieren eines neuen Kernels handelt es sich um einen recht komplexen Vorgang. Da teilweise als Root gearbeitet werden muss und da ein falsches Vorgehen dazu führen kann, dass das System sich nicht mehr booten lässt, ist äußerste Sorgfalt bei der Arbeit geboten. Bitte Abschnitte dieses Dokuments immer erst komplett zu Ende lesen, bevor zur Tat geschritten wird. Dieses Dokument bezieht sich primär auf die Installation eines Kernels der 2.6er Serie auf x86-Architekturen. Natürlich können hier nicht alle Eventualitäten berücksichtigt und Situationen erklärt werden, in die man im Laufe der Installation geraten kann; daher bitte erst verstehen, was die einzelnen Befehle bewirken und dann diese ausführen oder entsprechend den eigenen Bedürfnissen anpassen. Der Text ist in einer logischen Reihenfolge aufgebaut und kann daher Schritt für Schritt von vorne her abgearbeitet werden. Zusatzinformationen, weitergehende Erklärungen sowie wichtige Dinge, die es zu beachten gilt, sind in einer Box farbig unterlegt dargestellt und durch entsprechende Icons markiert:

info Anmerkungen
expl Erklärungen
warn Wichtig

Dateinamen o.ä (insbesondere wenn sie Versionsnummern beinhalten) sind in der Regel als Platzhalter zu verstehen und durch die jeweiligen tatsächlich vorhandenen Dateinamen oder Patches etc. zu ersetzen - dieses Howto kann natürlich nicht bei jeder neuen Kernel-Version angepasst werden. Dieser Text erhebt selbstverständlich keinen Anspruch auf Richtigkeit und Vollständigkeit und es wird keine Gewähr für alle Angaben oder daraus entstehender Konsequenzen übernommen (siehe auch den Disclaimer am Ende des Dokuments).

Zurück zum Anfang des Textes

Vorwort

Es gibt zahlreiche Gründe, die Linux Kernel-Quellen auf seinem System zu installieren, zu konfigurieren und sich einen eigenen Kernel zu compilieren. Eventuell möchte man in die Kernel-Programmierung einsteigen, Zugriff auf die Dokumentation erhalten, die zusammen mit den Kernel-Quellen installiert wird oder man möchte einfach etwas Neues lernen und hat Spaß daran. Es sei angemerkt, dass das Installieren eines neuen Kernels keine triviale Angelegenheit ist. Es ist daher immer eine gute Idee, ein aktuelles Backup sowie eine Notfall-CD zum Booten zur Verfügung zu haben. Hierfür eignet sich neben dem SUSE-Rettungssystem per CD/DVD vor allem auch die Knoppix-CD/DVD, erhältlich unter http://www.knopper.net/knoppix/.

Dieser Text bezieht sich primär auf die openSUSE-Linux-Distribution sowie auf i386-Architekturen; die hier gegebenen Informationen sollten sich aber auch leicht auf andere Distributionen und andere Architekturen (z.B. x86_64) übertragen lassen.

Dieses Howto soll Neulingen den Einstieg in das korrekte Installieren eines neuen Kernels erleichtern. Experten werden sicherlich hier keine neuen Informationen finden können. Es gibt zahlreiche Literatur zum Linux-Kernel in englischer Sprache, allerdings nur bedingt aktuelle Dokumentation in deutscher Sprache. Da ich immer wieder darauf hingewiesen wurde, wie schwer verständlich manchmal ein englischer Text für jemanden ist, der die englischen Sprache nur bedingt beherrscht, habe ich mich entschlossen, diese Anleitung (neudeutsch: Howto) hier in deutscher Sprache zu verfassen.

Das Howto sollte nicht als Anleitung und schon gar nicht als Aufforderung missverstanden werden, sich ohne große Gedanken mal so eben einen neuen Kernel zu installieren. Manche Kernel brauchen unter Umständen Updates weiterer Pakete (z.B. mkinitrd, module-init-tools, udev, o.ä.), um einwandfrei zu funktionieren. Kernel 2.6 wird stetig weiter entwickelt, es gibt momentan keinen separaten Entwicklerzweig des Kernels. Das bedeutet, dass neuere Versionen nicht immer 100% rückwärtskompatibel sein müssen. Die leider so weit verbreitete Einstellung, stets die neuste Version bei jeder Software haben zu müssen ("Versionitis"), ist beim Kernel sicherlich fehl am Platz! Sicherheitsupdates können bei SUSE-Systemen über YOU (YaST Online Update) eingespielt werden, das gilt auch für den Kernel. Auch KOTD müssen nicht aus den Quellen installiert werden, das entsprechende Verzeichnis auf dem FTP Server oder aus dem Build Service kann als YaST Installationsquelle hinzugefügt werden. Wenn man diesem Howto folgt, sollte man wissen, was man tut, d.h. die Dinge und den Text hier verstehen und sich im Klaren darüber sein, was es bedeutet. Wer unbedacht und ohne Sicherheitsvorkehrungen einen neuen Kernel installiert und es geht dabei etwas schief, darf nicht unbedingt mit Mitleid rechnen.

Ein Wort zu Kernel 2.6: Im Dezember 2003 wurde offiziell Kernel 2.6.0 freigegeben und zum stabilen Kernel deklariert. Die 2.6er Serie, die von Linus Torvalds verwaltet und gepflegt wird, ersetzt die bisherige stabile 2.4er Serie. Mit Kernel 2.6 halten etliche Erweiterungen und Verbesserungen Einzug in die Linux-Welt, sodass es durchaus auch eine 3.0 Version hätte geben können, zumindest war dies eine Zeit lang im Gespräch. Gab es bei der Einführung von Kernel 2.4 etliche Probleme (u.a. wegen Stabilitätsproblemen, dem Austausch des Virtual-Memory-Managements mitten in einer stabilen Serie oder Problemen von ReiserFS mit NFS - letztendlich musste Kernel-Release 2.4.11 sogar offiziell als "don't use" deklariert werden), so wurde bei der 2.6er Serie darauf geachtet, dass die wichtigsten Features bei der offiziellen Freigabe stabil und zuverlässig arbeiten. Hier einige der wichtigsten Änderungen:

Das sind nur einige der Änderungen, die sich beim Vergleich von Kerneln der 2.6er Serie mit Kerneln der 2.4er Serie ergeben. Der größte Fortschritt dürften sicherlich die verbesserten Latenz- und Skalierbarkeitseigenschaften sein, die Linux weiter gegenüber kommerziellen Unix-OS aufholen lassen.

Oft tauchen die Fragen auf, wie viel Festplattenkapazität man braucht, um einen Kernel zu übersetzen und wie lange das dauert. Hierzu folgende Daumenregeln: das Verzeichnis mit den Quellen zum SUSE-Kernel 2.6.16 ist nach dem Entpacken ca. 275MB groß. Beim Compilieren werden viele zusätzliche Dateien erstellt (Object-Files, Header-Files, usw.), sodass insgesamt wohl pro installiertem Verzeichnis mit momentan aktuellen Kernel-Quellen mit ca. 400MB benötigtem Festplattenplatz (bei Aktivierung nahezu aller Kernel-Features) zu rechnen ist. Neuere Kernel benötigen i.d.R. mehr Festplattenkapazität! Die zum Compilieren des Kernels benötigte Zeit hängt sehr von der Ausstattung des Rechners - insbes. dem Prozessor und der Menge an Speicher - ab, aber natürlich auch von der gewählten Kernel-Konfiguration. So kann es zwischen wenigen Minuten (aktuelle Rechner mit genügend RAM) bis hin zu vielen Stunden dauern bei älteren oder ganz alten Rechnern. Zum Glück ist es aber möglich, einen Kernel für eine ältere Maschine auch auf einem neuen und damit wohl schnelleren Rechner zu übersetzen.

Zurück zum Anfang des Textes

Die Kernel-Quellen

Bevor man mit dem Konfigurieren beginnen kann, braucht man natürlich erst einmal die Quellen des gewünschten Kernels. Es gibt mehrere Möglichkeiten, an die Quellen eines bestimmten Kernels zu gelangen:

Um sich schnell einen Überblick über die aktuellen Versionen des Vanilla-Kernels zu verschaffen, kann man die Seite http://www.kernel.org/kdist/finger_banner aufrufen.

SUSE- und Vanilla-Kernel-Quellen unterscheiden sich. Zwar basiert der SUSE-Kernel auf den Vanilla-Kernel-Quellen, jedoch werden einige SUSE-eigenen Patches angewandt. Sind einige dieser Patches mit für ein SUSE-System relevanten Features verbunden, so ist es möglich, dass ein reiner Vanilla-Kernel auf einem SUSE-System nicht reibungslos läuft.

Zum Download der Kernel-Quellen sollte man stets einen lokalen Mirror verwenden, um die original FTP-Server von kernel.org bzw. suse.com/opensuse.org zu entlasten. Eine Liste von Mirrorn findet man auf den openSUSE Webseiten unter http://de.opensuse.org/Spiegelserver_der_stabilen_Version oder unter http://www.novell.com/de-de/products/linuxprofessional/downloads/ftp/index.html. Eine Liste mit Mirrorn von kernel.org findet sich unter http://www.kernel.org/mirrors/. Des Weiteren spiegeln auch viele der in der SUSE-Liste aufgeführten Server einige Teile von kernel.org.

Verschiedene Kernel Flavors werden alle aus ein und denselben Quellen erstellt, d.h. es gibt nur ein RPM mit den Quellen des SUSE-Kernels. Diese Kernel unterscheiden sich nur in ihrer Konfiguration. Davon weicht momentan allerdings der Realtime-Kernel, kernel-rt, ab - dieser besitzt aufgrund umfangreicher Patches eigene Kernelquellen.

Bei den Paketen kernel-source-2.6.xx-y.rpm und kernel-source-2.6.xx-y.src.rpm handelt es sich um zwei unterschiedliche Pakete mit unterschiedlicher Zielsetzung. Will man die Kernel-Quellen installieren, so sollte man das hier zuerst genannte RPM nehmen. Beim zweitgenannten RPM handelt es sich um ein sog. Source-RPM. Installiert man dieses Source-RPM, so sucht man vergebens das Verzeichnis mit den Kernel-Quellen unter /usr/src/! Die Kernel-Quellen (als Tar-Archiv sowie evtl. Patches) wurden dann nämlich samt sog. spec-File nach /usr/src/packages/ in die Unterverzeichnisse SOURCES bzw. SPECS entpackt. So kann theoretisch das spec-File angepasst, die Kernel-Quellen gepatcht oder ein neues Source-RPM gebaut werden. Auf dieses Vorgehen soll hier nicht näher eingegangen werden. Details hierüber findet man im Handbuch "Maximum RPM" (in englisch) oder in "Das RPM Buch" (in deutsch).

Es gibt einige Personen, die offiziell Patches für Vanilla-Kernel zur Verfügung stellen bzw. verwalten. Patches mit dem Namen "-rc" sind sog. "release candidates", also Vorstufen der nächsten Kernelversion, die freigegeben wird - dieses Patchset wird von Linus Torvalds verwaltet. Andrew Mortons Patchset trägt die Ergänzung "-mm".

Seit Kernel 2.6.11 können Versionsangaben auch vierstellig sein. Dies wurde bereits einmalig bei Kernel 2.6.8 genutzt, um schnellstmöglich einen Bug-Fix veröffentlichen zu können. Die vierstelligen Releases beheben lediglich echte und bestätigte Fehler und beinhalten keine Neuerungen! Die vierte Zahl ergänzt die übliche Bezeichnung aus Major-Version ("2"), Minor-Version ("6") und Patch-Level (z.B. "11").

Zurück zum Anfang des Textes

Auspacken der Kernel-Quellen

Die Quellen des SUSE-Distributionskernels können einfach per YaST2 (oder einer anderen Paketmanagement-Software) installiert werden. Nach der Installation sollte sich unter /usr/src/ ein Verzeichnis mit den SUSE-Kernelquellen befinden. Ebenso wird vermutlich der Link /usr/src/linux auf das neue Verzeichnis mit den Kernel-Quellen zeigen. Falls die Kernel-Quellen nachinstalliert werden und der eigentliche Kernel bereits per YOU gepatcht wurde, so muss nun YOU erneut gestartet werden, um auch die Kernel-Quellen auf die aktuelle Version zu bringen.

Liegen die Kernel-Quellen im RPM-Format als Download vom openSUSE-FTP-Server vor und sollen parallel zu den Quellen des Standard-Distributionskernels installiert werden, so kann nicht einfach das Kommando "rpm -Uhv kernel-source.neu.rpm" benutzt werden, da dieser Befehl die bereits installierten Kernel-Quellen ersetzen würde. Je nachdem, wie das RPM-Paket gebaut wurde, kann es schlicht über den Befehl

$> su
$> rpm -ihv /pfad/zu/kernel-source.neu.rpm

installiert werden. Sollte RPM dabei über Konflikte klagen, so kann unter Umständen die RPM-Option "--force" weiterhelfen. Ein

$> su
$> rpm -ihv --force /pfad/zu/kernel-source.neu.rpm

sollte die Kernel-Quellen gegebenenfalls korrekt unter /usr/src/ in ein eigenes Verzeichnis installieren. Dies mag eine der wenigen Situationen sein, in denen die genannte RPM-Optionen benutzt werden darf. Generell sollte man von RPM gemeldete Konflikte nicht ignorieren! Mit "rpm -qpl /pfad/zu/kernel-source.neu.rpm" kann zuvor überprüft werden, in welches Verzeichnis sich genau die Kernel-Quellen installieren - so kann gegebenenfalls ein bereits mit gleichem Namen vorhandenes Verzeichnis verschoben bzw. umbenannt werden. Ebenso lässt sich so überprüfen, ob durch das RPM-Paket weitere Dateien außerhalb von /usr/src/ installiert werden. Vermutlich wird wiederum - wie bereits weiter oben erwähnt - der Link /usr/src/linux nach der Installation auf das neue Verzeichnis mit den Kernel-Quellen zeigen.

Liegen die Kernel-Quellen als komprimiertes Tar-Archiv vor (z.B. die Quellen des Vanilla-Kernel), so müssen diese mit dem Programm "tar" entpackt werden. Damit es zu keinen Konflikten kommt, sollte man vorher die Namen bereits vorhandener Kernel-Verzeichnisse unter /usr/src/ (das Verzeichnis, in dem Kernel-Quellen meist installiert werden) prüfen und eventuell (temporär) abändern.

$> su
$> cd /usr/src/
$> tar -xvjf /pfad/zu/linux-2.6.23.tar.bz2

bzw.

$> tar -xvzf /pfad/zu/linux-2.6.23.tar.gz

Es bietet sich an, das so entstandene Verzeichnis und alle darin enthaltenen Dateien einem normalen User (und der zugehörigen Gruppe) zu vermachen und den Kernel nicht als Root zu compilieren (das ist auch nicht nötig; lediglich zum Installieren sind Root-Rechte erforderlich). Daher kann ein

$> chown -R myuser linux-2.6.23
$> exit

ausgeführt werden (wir befinden uns weiterhin im Verzeichnis /usr/src). Der Platzhalter "myuser" ist natürlich wie bisher auch entsprechend zu ersetzen, ebenso muss natürlich der korrekte Name für das Verzeichnis mit den Kernel-Quellen angegeben werden. Nutzt man das beim Kernel 2.6 neue Feature des Build-Directory, so kann auf die Änderung des Verzeichniseigentümers verzichtet werden.

Bei Kernel 2.6 ist es möglich, ein sog. Build-Directory anzugeben. Normalerweise werden die Konfiguration des Kernels und die beim Compilieren entstehenden Dateien im gleichen Verzeichnisbaum wie der Kernel-Quellcode abgelegt. Bei Angabe eines Build-Directory können die Dateien in einem anderen Verzeichnis als dem Verzeichnis mit den Kernel-Quellen erstellt werden. So kann der eigentlich Bau des Kernels komplett vom Verzeichnis mit dem Quellcode getrennt werden, was für wesentlich mehr Flexibilität sorgt. Dieses Feature ist bei Kerneln der 2.4er Serie nicht enthalten. Die Benutzung eines Build-Directory wird durch die Angabe von "O=/pfad/zum/build/directory" beim make-Befehl ermöglicht - dadurch wird die Variable KBUILD_OUTPUT im Makefile gesetzt und alle zu erzeugenden Dateien werden fortan umgeleitet. Das Verzeichnis, dessen Name an make übergeben wird, muss natürlich existieren, sonst kommt es zu einem Fehler!

Es ist zu beachten, dass bei der Verwendung eines Build-Directory die Angabe von "O=/pfad/zum/build/directory" entweder bei jedem (im Folgenden noch näher erläuterten) make-Befehl benutzt werden muss, oder aber (und das ist der weitaus praktischere Weg) man wechselt nach dem Klonen oder Erzeugen einer Konfiguration in das Build-Directory und gibt fortran alle make-Befehle dort ein!

Als normaler User sollte man dann in das Verzeichnis ./Documentation unterhalb des Verzeichnisses mit den Kernel-Quellen wechseln und sich als Erstes die Datei "Changes" anschauen. In der Datei wiederum ist das Kapitelchen "Current Minimal Requirements" von Interesse: dort steht, welche minimalen Voraussetzungen für den Einsatz des neuen Kernels erfüllt sein müssen. Eventuell müssen einige Software-Pakete erneuert werden, bevor der neue Kernel zum Einsatz kommen kann. Installiert man die zum Standard-Distributionskernel gehörenden Quellen, so kann man sich das Überprüfen der minimalen Systemvoraussetzungen natürlich sparen, denn diese müssen zwangsläufig erfüllt sein. Selbstverständlich müssen bei Bedarf nur Pakete erneuert werden, die auch tatsächlich gebraucht werden: setzt man z.B. kein XFS Filesystem ein, so brauchen die zugehörigen Pakete nicht erneuert oder installiert werden, selbst wenn die "Current Minimal Requirements" dadurch nicht erfüllt werden.

Immer wieder kommt es zu Missverständnissen, was den Link /usr/src/linux angeht. Prinzipiell muss dieser Link nicht existieren (Linus Torvalds geht sogar soweit zu sagen, der Link sollte nicht existieren). Er ist zum Konfigurieren, Compilieren und Installieren eines neuen Kernels nicht nötig. Existiert dieser Link aber, so sollte er immer auf die Kernel-Quellen des momentan laufenden Kernels zeigen. Der Link wird (leider nachwievor) manchmal benutzt, wenn externe Kernel-Module compiliert werden; oft wertet das entsprechende Makefile nicht den Link /lib/modules/`uname -r`/build aus (was es eigentlich tun sollte), sondern vertraut darauf, dass /usr/src/linux korrekt gesetzt ist. Nur wenn die korrekten Linux-Header zum Compilieren des Modules eingebunden werden können, wird es auch zum Kernel passen und sich laden lassen. Sofern also beim Installieren von neuen Kernel-Quellen der Link /usr/src/linux existiert und auf ein existierendes Verzeichnis mit (älteren) Kernel-Quellen, die zum momentan laufenden Kernel passen, zeigt, kann er zunächst unberührt bleiben. Erst nachdem ein neuern Kernel compiliert, installiert und erfolgreich gebootet wurde, sollte der Link /usr/src/linux angepasst werden. Installiert man Kernel-Quellen per RPM, so wird u.U. der Link automatisch verändert. Hier sollte man als Anwender ein Auge darauf haben und gegebenenfalls von Hand einschreiten (oder den Link ganz löschen).

Jede Distribution kommt mit zwei Sets von Kernel-Headern daher: die "System Kernel Headers" und die "Kernel Source Headers". Die "System Kernel Headers" sind die Header-Dateien, die vom System wirklich benutzt werden. Jedes Programm aus dem sog. User-Space (also jedes Anwendungsprogramm) wird mit Hilfe dieser Header compiliert. Üblicherweise liegen diese Header-Dateien in /usr/include/asm und /usr/include/linux. Diese Dateien sollten nie ersetzt werden, außer bei einem Update der C Bibliothek (aber das ist selbst für Experten keine einfache Aufgabe und jedem normalen Anwender kann man vom Updaten der glibc nur abraten). Diese Header-Dateien können mit vielen unterschiedlichen Kerneln genutzt werden (es gibt Kompatibilitäts-Code) und sind Teil des glibc-Paketes. Sie werden normalerweise über das Paket linux-kernel-headers installiert. Jeder Anwender, der einmal eigene Programme compilieren will, sollte dieses Development-Paket installiert haben! Die "Kernel Source Headers" sind Teil der Kernel-Quellen. Diese Header-Dateien sollten im Quellcode von Anwendungsprogrammen nie direkt eingebunden werden (es gibt ganz wenige Ausnahmen). Bei älteren Linux-Distributionen waren /usr/include/linux und /usr/include/asm nur symbolische Links auf Unterverzeichnisse innerhalb der Kernel-Quellen in /usr/src/linux und enthielten somit keinen eigenen Satz von Header-Dateien. Deswegen musste dort der Link /usr/src/linux zwingend existieren. Eine derartige Konstellation ist heutzutage nicht mehr anzutreffen. Die "Kernel Source Headers" werden verwendet, um den Kernel selbst oder Kernel-Module zu compilieren. Das Makefile zum Compilieren von externen Kernel-Modulen sollte daher nicht darauf vertrauen, dass der Link /usr/src/linux existiert und korrekt ist (und damit die Header-Dateien im Unterverzeichnis ./include der Kernel-Quellen gefunden werden), sondern stattdessen den Link /lib/modules/`uname -r`/build auswerten.

Das Verzeichnis mit den Kernel-Quellen muss nicht unter /usr/src/ liegen, auch wenn es sich in der Vergangenheit so eingebürgert hat und bei den meisten Distributionen auch wirklich dort liegt; es kann prinzipiell auch in einem anderen Verzeichnis liegen. Es ist dann darauf zu achten, dass evtl. vorhandene Links /usr/src/linux und /lib/modules/`uname -r`/build korrekt gesetzt sind, sollten die Quellen nach dem Installieren der Module verschoben werden. Im Zweifelsfalle sollte der Link /usr/src/linux ganz gelöscht werden!

Zurück zum Anfang des Textes

Patchen der Kernel-Quellen

Unter Umständen ist es nötig, die Kernel-Quellen zu patchen, z.B. wenn man eine Vorversion eines neuen Kernels nutzen oder vorhandene Kernel-Quellen updaten möchte.

Beim Patchen gilt zu beachten: der Patch muss exakt zu den installierten Kernel-Quellen passen, sonst wird es nicht funktionieren oder es ist Handarbeit angesagt. Will man z.B. von den Vanilla-Kernelquellen 2.6.23 zur Version 2.6.24-rc3 aufsteigen, so muss der patch patch-2.6.24-rc3.bz2 (mag evtl. auch mit gzip komprimiert sein, dann trägt der Patch die Endung .gz) auf die Kernel-Quellen 2.6.23 angewendet werden. Patches der Form patch-2.6.x-yy.bz2 werden grundsätzlich auf die aktuelle stabile Version der Kernel-Quellen angewendet. Bei einem Patch patch-2.6.x-rc3.bz2 ist es also nicht nötig, zuerst die -rc1 und -rc2 Patches anzuwenden, sondern der Patch wird direkt auf die Quellen des Kernels 2.6.(x-1) angewendet. Davon zu unterscheiden sind inkrementelle Patches, diese tragen Namen der Form patch-2.6.x-yy-zz.bz2; wie der Name schon andeutet, müsste dieser Patch auf die Quellen des Kernels 2.6.x-yy (das ist bereits ein gepatchter Kernel) angewendet werden und würde diese zu Quellen des Kernels 2.6.x-zz machen. Klingt etwas kompliziert, ist es aber nicht, wenn man sich die Namenskonvention einmal bewusst macht.

Zum eigentlichen Patchen benötigt man das Programm "patch", was sich in einem eigenen RPM auf den CDs bzw. der DVD der Distribution befindet. Da die Patches in der Regel komprimiert sind, sollte man wie folgt vorgehen:

$> cd /usr/src/linux-2.6.x
$> gunzip -c /pfad/zu/patch.gz | patch -p1 --dry-run

bzw.

$> bunzip2 -c /pfad/zu/patch.bz2 | patch -p1 --dry-run

je nachdem, ob der Patch mit gzip oder bzip2 komprimiert ist. Die Option "--dry-run" sorgt dafür, dass zunächst keine Dateien verändert werden, sondern lediglich die Anwendung des Patches geprüft wird. Bei einem erfolgreichen Patch-Versuch darf man als Anwender nichts gefragt werden und auf dem Terminal-Fenster dürfen nur die Namen der erfolgreich gepatchten Dateien erscheinen. Wird bereits bei der allerersten zu patchenden Datei gemeldet, dass diese nicht gefunden wird, so ist vermutlich die Option -p1 beim Patch-Befehl falsch. Diese Option gibt an, wie viele / in den Dateinamen, die im Patch-File erwähnt werden, entfernt werden sollen. Das hängt davon ab, wie der Patch erstellt wurde - kommt es also zu o.a. Problem, so sollte man die Option -p anpassen (evtl. -p0 oder auch -p2). Ist der Testversuch schließlich erfolgreich, so kann das eigentliche Patchen durch Entfernen der Option "--dry-run" erfolgen:

$> gunzip -c /pfad/zu/patch.gz | patch -p1

bzw.

$> bunzip2 -c /pfad/zu/patch.bz2 | patch -p1

Passt ein Patch nicht exakt zu den Kernel-Quellen, so kann es vorkommen, dass einige Dateien nicht gepatcht werden können; in solch einem Falle werden Dateien mit der Endung .rej angelegt. Hat man ein bisschen Ahnung, so kann man versuchen, die abgelehnten Patches von Hand durchzuführen, das ist aber wirklich nur für Fortgeschrittene zu empfehlen. Um eine genaue Analyse vorzunehmen, empfiehlt es sich, die Ausgabe des Patch-Befehls mitzuprotokollieren; siehe dazu das Kapitel "Sonstiges".

Nach einem erfolgreichen Patch sollte man den Namen des Verzeichnisses mit den Kernelquellen anpassen. Hat man also z.B. einen Patch patch-2.6.24-rc3 auf die Kernel-Quellen 2.6.23 angewendet, so sollte mit einem

$> su
$> cd /usr/src/
$> mv linux-2.6.23 linux-2.6.24-rc3
$> exit

das Verzeichnis korrekt umbenannt werden. Zwingend notwendig ist das natürlich nicht, es dient aber dazu, den Überblick zu behalten. Wie immer ist das hier natürlich nur ein Beispiel und die Namen müssen für die tatsächlichen Gegebenheiten angepasst werden.

Zum Patchen kann auch das Skript ./scripts/patch-kernel im Verzeichnis mit den Kernel-Quellen benutzt werden. Eine kurze Hilfe gibt es durch Eingabe von

$> ./scripts/patch-kernel -h

im Hauptverzeichnis der Kernel-Quellen. Zum Patchen ganz allgemein, siehe auch

$> man patch

aber das versteht sich ja sicher von selbst :-) Meist wird zur Verwaltung von Kernel-Patches heutzutage das Programm "quilt" eingesetzt - siehe Andreas Grünbachers Introduction to Quilt aus dem Jahre 2005 für eine Übersicht.

Ein erfolgreich durchgeführter Patch kann durch die Option "-R" beim ansonsten identischen Patch-Befehl wie oben wieder rückgängig gemacht werden! Die Manual-Seite ist für diese Option leider etwas kryptisch, deswegen sei es hier explizit erwähnt.

Um auf der sicheren Seite zu sein und mit Sicherheit einen saubere Kernel-Quellbaum zu haben, kann folgender Befehl ausgeführt werden - dieser löscht alle generierten Dateien, eine evtl. vorhandene Konfiguration und zahlreiche evtl. vorhandene Backup-Dateien und versetzt den Kernel-Quellbaum damit in den Zustand, in dem er eigentlich sein sollte:
$> cd /usr/src/linux-2.6.x
$> make mrproper
Siehe dazu auch das Kapitel "Sonstiges".

Zurück zum Anfang des Textes

Klonen einer existierenden Kernelkonfiguration

Mitunter ist es nötig, eine bereits existierende Kernelkonfiguration auf neue Kernel-Quellen zu übertragen. Gerade für Anfänger ist es auch hilfreich, mit einer bereits funktionierenden Kernelkonfiguration zu starten und dann für einen eigenen Kernel entsprechende Änderungen an der Konfiguration vorzunehmen. Zum Klonen einer existierenden Konfiguration gibt es mehrere Möglichkeiten. Es hängt u.a. davon ab, ob ein Build-Directory eingesetzt wird oder nicht. Wie bereits angedeutet dient das Build-Directory dazu, die Dateien, die im Laufe der Konfiguration des Kernels und des Compilierens entstehen, vom Verzeichnis mit dem Kernel-Quellcode zu trennen.

Gehören die zu konfigurierenden Kernel-Quellen zum momentan laufenden Kernel, so wird man als User nichts gefragt werden. Sind die Kernel-Quellen neuer als der momentan laufende Kernel, so werden vermutlich beim Klonen einige Fragen gestellt werden, ob neue (andere) Features im Kernel aktiviert werden sollen. Diese Fragen müssen entsprechend beantwortet werden.

Bei der Verwendung von openSUSE-Kernel-Quellen und einem laufenden SUSE-Kernel bzw. der Verwendung von "Kernel .config support" (d.h., es gibt die Pseudo-Datei /proc/config.gz) kann eine Konfiguration auch wie folgt geklont werden:
$> cd /usr/src/linux-2.6.x
$> make cloneconfig && make modules_prepare
Dies funktioniert nicht bei Vanilla-Kerneln von kernel.org. Bei Einsatz eines Build-Directory lautet die Befehlssequenz entsprechend
$> cd /usr/src/linux-2.6.x
$> make O=/pfad/zum/build/directory cloneconfig && \
make O=/pfad/zum/build/directory modules_prepare

Zurück zum Anfang des Textes

Anpassen des Kernel-Releases

Bevor ein eigener Kernel compiliert wird, sollte man dafür sorgen, dass es auf dem System zu keinen Konflikten kommt. Das bedeutet im Prinzip, dass man dem Kernel einen eindeutigen Release-Namen geben sollte, sodass es zu keinen Namenskonflikten mit eventuell bereits auf dem System installierten Kerneln und deren Modulen kommen kann. Es ist kontraproduktiv diesen Schritt durchzuführen, wenn man lediglich eine Konfiguration geklont hat, um z.B. externe Kernel-Module für den laufenden Kernel zu übersetzen. Die hier aufgeführte Problematik tritt wirklich nur auf, wenn man einen eigenen Kernel komplett compilieren und zusätzlich zu einem anderen Kernel im System installieren möchte.

Warum ist das wichtig? Hierzu ein kleines Beispiel: nehmen wir an, bisher ist im System nur der Kernel 2.6.16-default installiert (als vmlinuz unter /boot) und die zugehörigen Module liegen in /lib/modules/2.6.16-default/. Nun möchte man einen zweiten Kernel erstellen und einige Punkte in der Konfiguration abändern und diesen neuen Kernel dann zusätzlich zum alten Kernel im System installieren. Klont man sich eine Konfiguration, ändert man entsprechend seinen Wünschen die Konfiguration ab und compiliert und installiert nun diesen Kernel und dessen Module im System, so hat man ein Problem: für diesen neuen eigenen Kernel werden die Module wahrscheinlich ins gleiche Verzeichnis unter /lib/modules installiert werden. Da sich die Konfiguration aber gegenüber dem alten Kernel geändert hat (evtl. hat man andere Feature als Modul realisiert oder einige Features fest in den Kernel compiliert), kommt es zum Konflikt! Ebenso kann es passieren, dass ein älterer Kernel andere Einträge in der Datei /etc/modprobe.conf verlangt als ein neuerer Kernel. So gibt es noch weitere mögliche Konfliktpotenziale. In diesem kleinen Abschnitt geht es darum, diese Konflikte zu verhindern.

Sowohl bei einem SUSE- als auch bei einem Vanilla-Kernel kann ein eindeutiges Release während der Kernel-Konfiguration vergeben werden (siehe dazu auch den nächsten Abschnitt). Man findet unter dem Punkt "General Setup" die Option "Local version - append to kernel release". Diese Option wird u.U. bereits den Eintrag "-default" tragen, wie es für Standard-SUSE-Kernel üblich ist. Den entsprechenden Eintrag kann man nun erweitern, sodass ein eindeutiges Release entsteht. Die Länge des Eintrags darf 64 Zeichen nicht überschreiten.

Das Kernel-Makefile ist in der Lage, den aktuell konfigurierten Release-Namen auszugeben:

$> cd /pfad/zum/build/directory
$> make kernelrelease

Es lässt sich also auf diese Weise leicht die aktuelle Release überprüfen.

Zurück zum Anfang des Textes

Durchführen der Kernel-Konfiguration

Zur Durchführung der Kernel-Konfiguration gibt es mehrere Möglichkeiten; die Konfiguration sollte, wie bereits erwähnt, als normaler User durchgeführt werden. Für eine (fast) automatische Konfiguration stehen folgende Möglichkeiten zur Verfügung (die Eingabe der Befehle erfolgt jeweils im Hauptverzeichnis mit den Kernel-Quellen):

Es ist zu beachten, dass die Konfigurationsmethoden mittels "defconfig", "allmodconfig", "allyesconfig", "allnoconfig" oder "randconfig" selten bis nie zu wirklich brauchbaren und für sein System nutzbaren Konfigurationen führen. Diese Arten, den Kernel zu konfigurieren, sind nur als Grundlage oder zu Testzwecken gedacht und die Konfiguration sollte daher mit einer der folgenden Methoden für seine wahren Bedürfnisse angepasst werden.

Bei der Konfiguration einzelner Punkte werden entsprechende Hilfetexte angeboten - diese sollte man auf alle Fälle durchlesen, solange man über ein Feature nicht im Klaren ist. Meist stehen dort auch Hinweise, was auszuwählen ist, wenn man diesen Konfigurationspunkt nicht im Detail versteht. Es ist nicht möglich, auf alle Punkte der Kernel-Konfiguration hier einzugehen, weil es a) den Rahmen dieses Textes sprengen würde, b) sich Features ändern oder neue Features dazu kommen und dieser Text daher stets veraltet wäre, und c) jedes Zielsystem anders ist und es schlicht zu viele Hardwarekonfigurationen gibt, um hier allgemeingültige Aussagen zu treffen. Einige wichtige Punkte bei der Kernel-Konfiguration sind jedoch:

Beim Konfigurieren von SUSE-Kerneln sollte wie bereits erwähnt unter der Rubrik "General Setup" eine gültige und möglichst eindeutige Angabe für den Eintrag "Local Version" gemacht werden. Diese Angabe bestimmt das Kernel-Release.

Vor oder beim Verlassen der Konfiguration muss diese abgespeichert werden, sonst gehen alle Einstellungen verloren. Zusätzlich kann man seine eigene Konfiguration in einer weiteren Datei mit beliebigem Namen speichern. Es empfiehlt sich aus Sicherheitsgründen, dies zu tun, denn eine .config Datei ist oftmals schnell überschrieben. Für diese separate Datei (das ist im Prinzip nur eine Kopie der .config aus dem System) sollte man sich einen entsprechend eindeutigen und wiedererkennbaren Namen überlegen. Selbstverständlich kann auch ein einfacher Kopierbefehl an der Kommandozeile ausgeführt werden, um die Datei zu sichern. Man sollte bedenken, dass bei Einsatz eines Build-Directory die Datei .config nicht im Verzeichnis mit den Kernel-Quellen, sondern im angegebenen Build-Directory abgelegt wurde.

Nach dem Konfigurieren der Kernel-Quellen sollte man nun beim Einsatz eines Build-Directory dorthin wechseln. Alle weiteren make-Befehle sind dann im Build-Verzeichnis ohne die Angabe "O=/pfad/zum/build/directory" zu machen. Entsprechend wird im Folgenden die explizite Angabe des Build-Directory bei make-Befehlen nicht mehr erfolgen.

Zurück zum Anfang des Textes

Compilieren des Kernels

Nach der Konfiguration des Kernels kann nun der neue Kernel compiliert werden. Das geschieht genau wie das Konfigurieren selbst als normaler User (nicht als Root). Für den Kernel kann auch direkt ein (rudimentäres) RPM-Paket gebaut werden. Darauf wird später noch etwas näher eingegangen. Ein

$> make

bzw.

$> make all

sollte nun den Kernel erstellen und die Module compilieren. Soll lediglich der Kernel selbst erstellt werden (aber keine Module), so kann der Befehl "make bzImage" (auf i386 Systemen) bzw. generell "make vmlinux" benutzt werden. Die Module selbst werden dann durch Eingabe von "make modules" gebaut. Sofern keine Fehlkonfiguration des Kernels vorliegt oder Bugs im Kernel-Quellcode oder dem benutzten Compiler zu Tage treten, sollte es zu keinen Fehlermeldungen im Laufe der Compilierung oder des Linkens kommen.

Besitzt das System, auf dem man den Kernel compilieren will, mehrere Prozessoren, so kann man davon Gebrauch machen und die Zeit zum Compilieren des Kernels verringern. Dazu lässt sich die Option "-j jobs" von make verwenden, über die man die Anzahl der parallelen Jobs (Kommandos) angeben kann. So könnte zum Beispiel das Compilieren des Kernels auch mit
$> make -j4
angestossen werden. Die Verwendung dieser make-Option ist in der Regel nur auf Mehrprozessorsystemen sinnvoll, allerdings kann ein make -j2 auch auf Single-Core-Systemen von Vorteil sein.

Was passiert eigentlich genau durch den Befehl "make bzImage" bzw. "make vmlinux"? Das ist prinzipiell abhängig von der Architektur; hier sei daher nur auf die x86-Familie eingegangen. Zunächst werden die C und Assembler Quelldateien compiliert zu ELF (Executable and Linking Format) Object-Files (.o); dabei werden einige logisch gruppiert und zu Archiven (.a) zusammengefasst. Mit Hilfe des Linkers ld werden die Object-Files und die Archive statisch zu vmlinux gelinkt. Durch "nm vmlinux" wird die Datei System.map produziert. Im Verzeichnis ./arch/i386/boot/ wird der Bootsektor Assemblercode bootsect.S vorprozessiert zu bbootsect.s, dann verarbeitet und in ein raw binary namens bbootsect umgewandelt. Danach wird der Setupcode setup.S vorprozessiert zu bsetup.s und dann wiederum umgewandelt in ein raw binary namens bsetup. Nach dem Wechsel ins Verzeichnis ./arch/i386/boot/compressed/ wird <source-Verzeichnis>/vmlinux ins raw binary Format konvertiert, die ELF Sektionen .note und .comment entfernt und unter einem temporären Namen gespeichert. Anschließend wird per "gzip -9" die temporäre Datei komprimiert und per "ld -r" ins ELF format gebracht und unter piggy.o gespeichert. Die Kompressionsroutinen head.S und misc.c werden compiliert zu head.o und misc.o und dann zusammen mit piggy.o zu bvmlinux gelinkt. Wiederum wird bvmlinux ins raw binary Format gebracht (unter Entfernung der ELF Sektionen .note und .comment) und als bvmlinux.out gespeichert. Letztendlich werden in ./arch/i386/boot/ mit Hilfe von ./arch/i386/boot/tools/build die Dateien bbootsect, bsetup und compressed/bvmlinux.out zur Datei bzImage zusammengefügt.

Das Kernel-Image ist komprimiert. Es sei hier erwähnt, dass der name "bzImage" nichts mit dem Programm bzip2 zu tun hat. Der Kernel ist mit dem gzip-Algorithmus komprimiert. Das "bzImage" steht für "big zImage". Früher, als das Kernel-Image noch kleiner war, wurde der Kernel üblicherweise mit dem Kommando "make zImage" erstellt. Der Unterschied zwischen "zImage" und "bzImage" besteht in einem unterschiedlichen Layout und einem unterschiedlichen Algorithmus zum Laden des Kernels, wodurch ein Kernel mit "make bzImage" erstellt eine größere Kapazität haben kann. Das liegt daran, dass der Linux-Kern hier direkt in den Speicher jenseits der 1MB-Grenze des Real-Modes geladen werden kann.

Kommt es beim Compilieren des Kernels zu einem Fehler und der Vorgang bricht mit "Signal 11" oder einem "Segmentation Fault" ab, so ist die wahrscheinliche Ursache hierfür ein Hardware-Fehler! Meist ist es ein defekter Speicherriegel, der Probleme verursacht. Selbst ausgereifte Speichertestprogramme beanspruchen das RAM selten so wie der GCC beim Compilieren eines Kernels, man führt quasi gleichzeitig mit dem Compilieren des Kernels noch ein Hardwaretest durch. Versucht man das Compilieren nach einem Abbruch erneut mit "make" anzustoßen und kommt der Vorgang dann ein wenig weiter als vorher, bricht schließlich aber erneut mit "Signal 11" ab, so handelt es sich sicher zu 99.9% um einen Hardwarefehler. Bei den hier genannten Problemen sollte man die Seite http://www.bitwizard.nl/sig11/ aufsuchen.

Möchte man mit seiner erstellten Konfiguration ein Kernel-RPM bauen, so ist das bei Kernel 2.6 sehr leicht möglich; dabei wird auch ein Source-RPM erzeugt. Das Kernel-RPM kann später sehr einfach im System installiert werden, es muss eventuell nur noch eine Initial Ramdisk für den Kernel kreiert und die Bootloader-Konfiguration angepasst werden. Das RPM wird durch Eingabe von

$> make rpm-pkg

bzw.

$> make binrpm-pkg

erstellt (je nachdem, ob auch ein Source-RPM benötigt wird). Statt "make rpm-pkg" kann auch einfach "make rpm" verwendet werden. Je nach Systemkonfiguration sind zum Erstellen des RPMs Root-Rechte erforderlich. Das fertige RPM mit dem compilierten Kernel und dessen Module wird man unter /usr/src/packages/RPMS/ und das Source-RPM in /usr/src/packages/SRPMS/ finden. Baut man ein RPM, so kann man sich das explizite Compilieren des Kernels und der Module (make bzw. make bzImage und make modules) sowie natürlich später die Installation des Kernels von Hand und der Module (make modules_install) sparen. Stattdessen muss das erstellte Binary-RPM installiert werden (Erstellung einer Initial Ramdisk nicht vergessen, falls nötig).

Das fertige Binary-RPM wird (auf 32-bit Linux Systemen) normalerweise im Verzeichnis /usr/src/packages/RPMS/i386/ landen, unabhängig von eventuell gewählten RPM-Optionen. Das liegt daran, dass die Architektur des Systems im Kernel als i386 bezeichnet wird, d.h. das Kernel-Makefile ersetzt alle i?86 durch i386. Dennoch bedeutet dies nicht, dass der Kernel beim Compilieren mit der Option "-march=i386" übersetzt wird. Das liegt an arch/i386/Makefile, dem architekturabhängigen Teil des Kernel-Makefiles, das wiederum anhand der Prozessorwahl der Kernel-Konfiguration optimale Compilerflags ermittelt. Wird z.B. bei der Kernel-Konfiguration eine Pentium-M CPU ausgewählt, dann wird beim Compilieren des Kernels auch "-march=i686" verwendet. Das Kernel-Makefile ermittelt optimale Compiler-Flags anhand des Zielsystems selbst, was auch gut so ist. RPM-Optionen wie "--target=i686" werden ignoriert, weil dies ansonsten zu Konflikten mit dem gewählten Prozessortyp bei der Kernel-Konfiguration führen könnte (der neue Kernel wäre damit auf einem Zielsystem evtl. nicht lauffähig).

Zurück zum Anfang des Textes

Installation des Kernels

Nach dem Compilieren des Kernels und der zugehörigen Module muss der Kernel nun installiert werden. Hier wird davon ausgegangen, dass obige Hinweise zum Anpassen des Kernel-Releases berücksichtigt wurden; ansonsten kann es zu Problemen kommen, insbesondere wenn ein eigens compilierter Kernel mit dem SUSE Standard-Kernel kollidiert und die Module in das gleiche Verzeichnis installieren will. Es sei zudem vorerst davon ausgegangen, dass kein Kernel-RPM erstellt wurde.

Zunächst müssen die Module installiert werden; dieser Schritt (und die folgenden zum Installieren des Kernels im System sowie der Anpassung des Boot-Loaders) ist nur als Root möglich. Wir befinden uns weiterhin im Hauptverzeichnis unserer Kernel-Quellen bzw. in unserem Build-Directory:

$> su
$> make modules_install

Durch das Kommando werden die zuvor compilierten Module unter /lib/modules/ installiert, und zwar in ein Verzeichnis, welches den Namen der Variablen UTS_RELEASE aus der Datei ./include/linux/version.h besitzt. Das entspricht auch der Ausgabe, die ein "make kernelrelease" sowie ein "uname -r" nach dem Booten des neuen Kernels liefern würde. Durch das Kommando sollte auch automatisch ein "depmod -ae" zum Aktualisieren der Module-Abhängigkeiten ausgeführt werden.

Nun sollte der neu erstellte Kernel sowie die neue Datei System.map (als Root) nach /boot kopiert werden. Dabei ist zu beachten, dass die kopierten Dateien im Verzeichnis /boot mit der gleichen Endung versehen werden; diese Endung sollte wiederum dem Namen des Verzeichnisses, in das die Module installiert wurden (= Kernel-Release), entsprechen. Gehen wir hier z.B. davon aus, dass wir einen Kernel 2.6.24-th1 erstellt haben, so wurden die Module in das Verzeichnis /lib/modules/2.6.24-th1 installiert und wir sollten nun

$> cp ./arch/i386/boot/bzImage /boot/vmlinuz-2.6.24-th1
$> cp ./System.map /boot/System.map-2.6.24-th1

ausführen. Man beachte, dass zwischen dem Namen der Datei und der Versionsangabe ein Bindestrich hinzukommt.

Hat man für den neuen Kernel ein RPM-Paket erstellt, so müssen bzw. dürfen die Module sowie der Kernel und die Datei System.map nicht von Hand (wie oben angegeben) installiert werden. Stattdessen wäre nun das gebaute Binary-RPM-Paket als Root zu installieren. Da das verwendene spec-File zum Erstellen des Kernel-RPMs sehr einfach gehalten ist, wird eine Initial Ramdisk nicht automatisch generiert durch ein RPM-Postinstall-Script. Eine Initial Ramdisk muss daher von Hand wie unten angegeben erstellt werden. Alternativ kann theoretisch ein Kernel-RPM mit einem angepassten original SUSE-Kernel-Spec-File generiert werden. Dann würden manuell durchzuführende Schritte quasi komplett entfallen. Allerdings ist diese Methode sicherlich nur für fortgeschrittene User mit Kenntnissen zum Bau von RPM-Paketen zu empfehlen.

Die Datei System.map, die über das Programm "nm" produziert wird, enthält die Namen und Adressen von Symbolen des Linux Kernels. Sie ist für den Alltag eines Linux-Systems nicht lebenswichtig. Die Datei System.map wird prinzipiell zum Debuggen bei Kernel-Problemen gebraucht.

Was ist eigentlich ein Oops? Wer selbst eigene Software programmiert, der wird einen berühmten Fehler kennen: Signal 11, auch "Segmentation Fault" genannt. Einen ähnlichen Fehler kann es natürlich z.B. auch beim Linux-Kernel geben. Dereferenziert der Linux Kernel z.B. einen ungültigen Pointer, so kann das schwerwiegende Auswirkungen haben. Ein Oops ist also ein Hinweis auf einen Kernel-Bug und sollte immer gefixt werden. In anderen Worten: ein Oops ist die Art des Kernels dem User mitzuteilen, dass etwas Unangenehmes vorgefallen ist (was genau schief gelaufen ist, lässt sich nur durch Analyse des Oops sagen). Der Linux Kernel ist aber relativ robust und - im Gegensatz zu einem Segmentation Fault bei einem eigenen Programm - muss der Kernel dadurch nicht instabil werden oder gar abstürzen. Ein Oops hat also nichts mit einem Kernel-Panic zu tun. Bei einem Kernel-Panic ist der Linux Kernel in einem Zustand, bei dem es nicht mehr weiter geht - das System muss rebootet werden. Natürlich kann ein Oops einen Kernel-Panic verursachen, wenn der Fehler in einem lebenswichtigen Teil des Kernel-Codes auftritt. Tritt der Fehler nur in einem Gerätetreiber auf, so wird es vermutlich nicht zu einem Kernel-Panic kommen - der Kernel wird sich lediglich mehr oder weniger elegant aus dem Kontext zurückziehen und versuchen, die Situation unter Kontrolle zu bringen. Folge kann auch sein, dass Prozesse hängenbleiben, weil z.B. eine Resource durch einen Oops in einem anderen Thread nicht wieder freigegeben wurde. Der Oops wird über die üblichen Wege meist in /var/log/messages festgehalten.

Gegebenenfalls ist nun eine Initial Ramdisk für den neuen Kernel zu erstellen (wiederum als Root):

$> cd /boot
$> mkinitrd -k vmlinuz-2.6.24-th1 -i initrd-2.6.24-th1

Wie man sieht, sollte auch die Initial Ramdisk mit einer Versionsnummer versehen werden. Die Optionen "-k" und "-i" müssen hier benutzt werden, da sonst die Initial Ramdisk nicht für den neuen, sondern für den momentan noch laufenden Kernel erstellt würde. Die Module, die in die Initial Ramdisk aufgenommen werden, werden der Datei /etc/sysconfig/kernel entnommen (Variable: INITRD_MODULES). Will man andere Module in die Initial Ramdisk aufnehmen, so können deren Namen per Option "-m" bei mkinitrd angegeben werden. Siehe auch "mkinitrd -h" für eine Hilfe zum Programm. Ein Splash-Bildschirms sollte automatisch berücksichtigt werden. Hierbei wird u.a. die Datei /etc/sysconfig/bootsplash ausgewertet. Für Details zu bootsplash (auch zum Einsatz eigener Themes), siehe http://www.bootsplash.org/.

Zum Installieren des Kernels steht auch das Kommando "make install" zur Verfügung. Aber Vorsicht: dadurch werden symbolische Links im Verzeichnis /boot verändert, welche die Standardeinträge in der Bootloader-Konfigurationsdatei betreffen können. Es kann daher passieren, dass man seinen alten, funktionierenden Kernel nach einem Reboot zwar noch auswählen kann, dahinter aber letztendlich doch der neue Kernel steckt und daher der alte Kernel faktisch nicht mehr gebootet werden kann. Entweder muss man also im Anschluss an make install die Standardeinträge für die SUSE-Default-Kernel überprüfen und ggf. anpassen, oder aber man installiert den Kernel wie hier angegeben von Hand - letzteres halte ich für die sicherere Methode, da alle Schritte einzeln durchgeführt und stets überprüft und angepasst werden können.

Nun muss noch die Konfiguration des Bootloaders angepasst werden, um den neuen Kernel booten zu können. Das wird im folgenden Abschnitt beschrieben.

Zurück zum Anfang des Textes

Anpassen der Bootloader-Konfigurationsdatei

Wird LILO als Bootloader benutzt, so muss die Datei /etc/lilo.conf (als Root) angepasst werden. Die Datei ist um einen Abschnitt für den neuen Kernel zu ergänzen; man kann sich dabei an den bereits existierenden Sektionen in der Datei orientieren. So ein Eintrag könnte in unserem Beispiel wie folgt aussehen:

[...]
image = /boot/vmlinuz-2.6.24-th1
       label = linux2618
       append = "selinux=0 splash=0 resume=/dev/hda7 showopts"
       initrd = /boot/initrd-2.6.24-th1
       optional
       root = /dev/hda6
[...]

Die entsprechenden Optionen, die hier gesetzt sind, können "man lilo.conf" entnommen werden; sie sind dort ausführlich erklärt. Desweiteren sollte man neben der bereits genannten Lektüre noch "man lilo" und die Dateien unter /usr/share/doc/packages/lilo/ lesen.

Findet sich ein Eintrag "default" in /etc/lilo.conf, so wird der mit diesem Label spezifizierte Kernel per default geladen, ansonsten ist es der Kernel des ersten Eintrags "image" oder "other" (was also u.U. auch ein anderes Betriebssystem als Linux sein kann). Einen neuen Kernel sollte man zunächst einmal nicht per default booten, sondern beim Booten im Menü oder am LILO-Prompt auswählen. Stellt sich heraus, dass der neue Kernel erfolgreich bootet und eingesetzt werden kann, so kann die Datei /etc/lilo.conf entsprechend angepasst und der neue Kernel als Standard gebootet werden.

Nach der Änderung der Datei /etc/lilo.conf ist der Bootloader (als Root) wie üblich neu zu installieren:

$> /sbin/lilo

Dabei werden die Labels aus /etc/lilo.conf gelistet, der Eintrag, der als Standard gebootet wird, ist durch einen * (Stern) gekennzeichnet.

Nun aber zum Bootloader GRUB: Der größte Unterschied zwischen LILO und GRUB besteht darin, dass GRUB seine Konfiguration beim Booten direkt aus /boot selbst lesen kann. GRUB muss daher nach Änderungen an der Konfiguration nicht neu installiert werden. Die Konfigurationsdatei liegt in /boot/grub/ und heißt menu.lst. Hier ein Beispiel wie menu.lst aussehen kann:

default 0
title linux
       root (hd0,5)
       kernel /boot/vmlinuz root=/dev/hda6 vga=0x342 resume=/dev/hda7 showopts
       initrd /boot/initrd
title linux2624
       root (hd0,5)
       kernel /boot/vmlinuz-2.6.24-th1 root=/dev/hda6 vga=0x342 resume=/dev/hda7 showopts
       initrd /boot/initrd-2.6.24-th1

Dabei bedeuten

Alternativ zu obigen Beispiel könnte man auch

       kernel (hd0,5)/boot/vmlinuz-2.6.24-th1 root=/dev/hda6 vga=0x342 resume=/dev/hda7 showopts
       initrd (hd0,5)/boot/initrd-2.6.24-th1

schreiben, wobei man sieht, dass man initrd auch auf anderen Partitionen ablegen kann.

Ein Device wird in der Notation, die GRUB verwendet, als (hdX,Y) angegeben. Dabei steht X für die Festplatte - die Zahl beginnt bei 0 und entspricht der Nummer der gefundenen Festplatten beim Booten; die Reihenfolge wird durch das System-BIOS festgelegt. Y ist die Partition auf der entsprechenden Festplatte, auch hier beginnt die Zählung bei 0. Im Beispiel der GRUB-Konfigurationsdatei oben entspräche (hd0,5) der sechsten Partition auf der ersten Festplatte. Ist /boot eine eigene Partition und nicht Teil der Root-Partition, so ist ggf. bei den Optionen kernel und initrd ein Eintrag der Art "(hd0,0)/vmlinuz-2.6.24-th1" bzw. "(hd0,0)/initrd-2.6.24-th1" nötig, wobei die Angabe der entsprechenden Partition wie oben erklärt erfolgt.

Ausführliche Informationen zur Konfiguration erhält man mit "man grub" bzw. "info grub" und natürlich in /usr/share/doc/packages/grub/. Auch hier gilt wieder, einen neuen Kernel besser erst einmal nicht als Standard zu laden bis sichergestellt ist, dass er einwandfrei lauffähig ist.

Module, die nicht Teil der Kernel-Quellen sind (wie z.B. Kernelmodule bekannter Grafikchiphersteller) müssen für einen neuen Kernel nach dem ersten Booten neu übersetzt und installiert werden! Im Falle der Grafikkarten-Treiber sollte man daher das System durch Eingabe von "3" am Bootprompt direkt in Runlevel 3 (und nicht in Runlevel 5, wie es oft der Standard ist) booten. Anschließend kann man als Root an der Konsole das Kernel-Modul für den Grafikkartentreiber neu übersetzen und installieren. Siehe hierzu die entsprechende Dokumentation des Grafikkartentreiberpakets.

Nach der Installation des Kernels (und evtl. dem Anpassen der Datei /etc/modprobe.conf) muss nun der Rechner rebootet werden. Wurden alle Schritte korrekt ausgeführt, so sollte sich der neue Kernel ohne Probleme booten lassen.

Zurück zum Anfang des Textes

Probleme beim Booten des neuen Kernels

Beim Booten des neuen Kernels mag einem entweder an der Konsole oder aber in /var/log/boot.msg die folgende Meldung auffallen:
Inspecting /boot/System.map-2.6.13-15.11-default
Loaded 24247 symbols from /boot/System.map-2.6.13-15.11-default.
Symbols match kernel version 2.6.13.
No module symbols loaded - kernel modules not enabled.
Diese Meldung kommt nicht direkt vom Kernel, sondern von klogd, dem Kernel Log Daemon. Sie stammt aus der Datei ksym_mod.c der sysklogd-Quellen. Hier wird eine veraltete Methode verwendet (get_kernel_syms), um an Informationen über Module zu gelangen. In "man get_kernel_syms" findet man auch entsprechend einen Hinweis: Because of these limitations, this system call is deprecated in favor of query_module. Das Problem produziert letztendlich oben genannte Fehlermeldung bei Kernel 2.6, obwohl evtl. (falls CONFIG_MODULES=y in der Konfigurationsdatei .config steht) Module verwendet werden. Das Module-Handling wird in diesem Fall trotz der Meldung korrekt funktionieren, daher nicht verunsichern lassen! Möchte man die Meldung loswerden, so braucht man eine gepatchte Version von sysklogd.

Beim Booten des neuen Kernels treten mitunter Probleme auf. Das deutet darauf hin, dass einige Punkte beim Konfigurieren oder Installieren des Kernels nicht beachtet wurden. Darunter fallen z.B.:

Bei Boot-Problemen kann unter Umständen auch folgender Artikel weiter helfen: Oliver Diedrich (odi), "Wenn der Pinguin nicht abhebt: Erste Hilfe bei Linux-Startproblemen", Praxis PC-Selbsthilfe: Linux, lilo, grub, ext2, ext3, reiserfs, fsck, c't 26/01, Seite 130.

Zurück zum Anfang des Textes

Sonstiges

Durch den hier genannten Befehl wird auch eine eventuell vorhandene Konfigurationsdatei .config gelöscht! Möchte man diese erhalten, so muss sie vor dem Ausführen des obigen Befehls gesichert werden.

Durch Eingabe von "make help" erhält man eine kurze Hilfe (in englisch) über mögliche Targets des Makefiles. Hier werden die meisten der in diesem Text erwähnten Befehle kurz zusammengefasst.

Zurück zum Anfang des Textes

Installieren mehrerer Kernel per RPM

Häufig kommt es vor, dass man neben dem eigentlichen Standard-Kernel, der bereits beim Aufspielen der SUSE-Linux Distribution im System installiert wurde, einen anderen SUSE-Kernel (z.B. einen neuen Test-Kernel vom SUSE-FTP-Server) installieren möchte. Der Einfachheit wegen wäre es schön, wenn man das über ein RPM-Kommando tun könnte und nicht die Kernel-Quellen selbst übersetzen müsste, schließlich werden von SUSE explizit Binary-RPMs angeboten (oder man hat sich ein eigenes Kernel-RPM gebaut, siehe oben). Mit

$> rpm -ihv neuer-kernel.rpm

kann man versuchen, das neue Kernel-RPM zu installieren. Sollte das gelingen (evtl. das manuelle Erstellen einer Initial Ramdisk nicht vergessen), so kann man die Bootloader-Konfiguration überprüfen und ggf. anpassen. Damit wäre das Thema auch schon abgeschlossen. Wie bereits früher erwähnt, kann das SUSE-KOTD-Verzeichnis als zusätzliche YaST-Installationsquelle angegeben werden, sodass sich KOTD-Kernel auch einfach über das Software Management-System von SUSE installieren lassen (hier handelt es sich aber nicht um Parallelinstallationen mehrerer Kernel).

Das Kommando "rpm -Uhv neuer-kernel.rpm" wird den momentan installierten Kernel durch den neuen Kernel ersetzen! Es ist auf diese Weise nicht möglich, Kernel parallel zu installieren.

Um herauszufinden, welches Kernel-RPM momentan auf dem System installiert ist, kann man das Kommando "rpm -qa 'kernel*'" benutzen.

Je nachdem, wie die zu installierende RPM Datei erstellt wurde, kann es beim Installationsversuch aber auch dazu kommen, dass Konflikte gemeldet werden. Was nun? Um das Problem zu lösen, gibt es mehrere Möglichkeiten. Mit dem Kommando

$> rpm -qpl neuer-kernel.rpm

kann man sich im Detail anschauen, welche Dateien im System installiert werden. Sollten dabei keine gravierenden Konflikte mit bereits auf dem System installierten Kerneln festgestellt werden, so kann mit den RPM-Optionen "--force" das neue Kernel-RPM installiert werden. Dadurch wird neben dem Erstellen des Module-Verzeichnisses unter /lib/modules/ (das die Module des neuen Kernels enthält) auch das Kernel-Image unter /boot abgelegt. Eine nötige Initial Ramdisk sollte beim Installieren von SUSE-Kerneln korrekt angelegt werden, ansonsten (z.B. bei selbst erstellten Vanilla-Kernel-RPMs) ist das von Hand wie im Abschnitt über die Installation des Kernels beschrieben nachzuholen. Achtung: ein Entfernen des SUSE Standard-Kernels führt dazu, dass fortan keine Kernel-Updates mehr per YOU eingespielt werden. Nutzt man einen eigenen selbst erstellten Kernel, so ist man selbst für Updates verantwortlich.

Damit sowohl der alte als auch der neue Kernel erfolgreich gebootet werden können, müssen nun ggf. noch die Bootloader-Konfigurationsdateien angepasst werden. Das Prinzip hierfür ist im Abschnitt zum Bootloader beschrieben. Achtung: die Namen und Abschnitte, die in die Bootloader-Konfigurationsdatei eingetragen werden, sollten genau kontrolliert werden, da ansonsten unter Umständen ein Booten nicht mehr möglich ist.

Für den neuen Kernel sind externe Kernel-Module in der Regel neu zu erstellen (compilieren) und dann zu installieren.

Zurück zum Anfang des Textes

Installieren externer Kernel-Module

Mitunter kommt es vor, dass man externe Kernel-Module, die nicht Teil des Kernel-Quellbaums sind, installieren möchte oder updaten muss, da ein Kernel-Modul in der Regel nur mit genau einer Kernel-Version funktioniert. Kernel-Module können unter Umständen auch mit nicht exakt zum Modul passender Kernel-Version verwendet werden, wenn der sog. "modversions" Mechanismus (kann bei der Kernel-Konfiguration angegeben werden) zur Verfügung steht. In diesem Falle werden jedem Symbol (Variable, Funktion), das der Kernel exportiert, eine Checksumme beigefügt. So steht (hoffentlich) genügend Information zur Verfügung, um Veränderungen am Kernel zu entdecken, die das Modul inkompatibel mit der Kernel-Version machen. In jedem Falle ist es aber besser (sofern möglich), ein Modul exakt für den Kernel zu compilieren, mit dem es dann auch im Betrieb funktionieren soll.

Um ein externes Modul zu übersetzen, müssen gewisse Header-Dateien des Kernels eingebunden werden. In anderen Worten, der Kernel-Source muss korrekt konfiguriert sein. Hat man sich aus den Quellen einen eigenen Kernel compiliert und installiert und danach die Konfiguration des Kernels nicht mehr verändert, so sind die Kernel-Quellen bereits konfiguriert. In allen anderen Fällen sollte man ggf. wie im Abschnitt zum Klonen einer Konfiguration beschrieben vorgehen. Wichtig dabei ist, den Befehl "make modules_prepare" nicht zu vergessen, da dieser unter anderem genau die vom externen Kernel-Modul eingebundenen Header-Dateien (wie z.B. linux/version.h) erzeugt.

Die exakte Vorgehensweise zum Erstellen des externen Kernel-Moduls hängt u.a. davon ab, wie das zugehörige Makefile des Moduls aussieht. In der Regel wird davon ausgegangen, dass der Kernel, für den das Modul zu erstellen ist, momentan läuft, d.h. gebootet ist.

Zum eigentlichen Erstellen des externen Kernel-Moduls wechselt man nun in dessen Source-Verzeichnis. Dort kann mit dem Befehl

$> make -C /pfad/zum/build/directory M=$(pwd) modules

das externe Modul (hoffentlicht) übersetzt und dann (als Root) mit

$> make -C /pfad/zum/build/directory M=$(pwd) modules_install

installiert werden. Wurde ursprünglich kein Build-Directory verwendet, so ist bei der Option "-C" entsprechend das Verzeichnis mit den konfigurierten Kernel-Quellen anzugeben (statt des Build-Directory). Ein Lesen der Dokumentation des Moduls kann weitere Hinweise darauf geben, wie das Modul compiliert werden muss. Im Zweifelsfalle hilft nur, sich das Makefile im Verzeichnis des zu erstellenden Moduls anzuschauen und zu analysieren.

Zurück zum Anfang des Textes

Der Boot-Prozess

Das Booten wird im PC vom BIOS übernommen. Nach dem Abschluss des Power-On SelfTests (POST) versucht das BIOS, den ersten Sektor der ersten Diskette, den sog. Boot-Sektor, zu laden. Schlägt dies fehl, so versucht das BIOS den Boot-Sektor von der ersten Festplatte zu lesen. Aktuelle BIOS-Versionen können die Reihenfolge zum Abfragen der Boot-Sektoren der unterschiedlichen Geräte (Floppy, Festplatte, CD-ROM, Netzwerk, usw.) nahezu beliebig festlegen. Das Booten des Betriebssystems läuft dann meist in mehreren Schritten ab. Da im Boot-Sektor sehr wenig Platz für Code ist, lädt dieser meist einen zweiten Lader nach, usw., bis dann endgültig der eigentliche Betriebssystemkern geladen ist. Der Aufbau eines Boot-Sektors ist prinzipiell recht einfach, seine Länge beträgt stets 512 Bytes. Der Code beginnt bei Offset 0 und der Boot-Sektor endet immer mit der Magic Number 0xAA55.

Das Booten von Diskette ist einfach, da jede Diskette genau einen Boot-Sektor hat. Festplatten können in Partitionen unterteilt sein, daher ist das Booten von Festplatte etwas schwieriger. Das BIOS weiß davon aber erst einmal nichts, sodass es einfach ebenso den ersten Sektor liest, auch Master Boot Record (MBR) genannt. Der MBR besitzt denselben Aufbau wie jeder andere Boot-Sektor, d.h. der Code beginnt bei Offset 0 und bei Offset 0x1FE steht die Magic Number 0xAA55. Am Ende des MBR steht die Partitionstabelle, die stets vier Einträge hat. Jeder Eintrag der Partitionstabelle ist 16 Bytes groß (Boot-Flag: 1 Byte; Kopfnummer des Partitionsbeginns: 1 Byte; Sektor und Zylindernummer des Boot-Sektors: 2 Bytes; Systemcode: 1 Byte; Kopfnummer des Partitionsendes: 1 Byte; Sektor und Zylindernummer des letzten Sektors der Partition: 2 Bytes; relative Sektornummer des Startsektors: 4 Bytes; Anzahl der Sektoren in der Partition: 4 Bytes). Eine Festplatte kann also in vier Partitionen unterteilt werden, die sog. primären Partitionen. Sollte das nicht ausreichen, kann eine sog. erweiterte Partition angelegt werden. Diese enthält wiederum mind. ein logisches Laufwerk. Der Aufbau des ersten Sektors einer erweiterten Partition entspricht einfach dem Aufbau des MBR. Der erste Partitionseintrag dieser erweiterten Partitionstabelle enthält das erste logische Laufwerk der Partition. Der zweite Eintrag wird als Zeiger benutzt, falls weitere logische Laufwerke existieren. Er zeigt dann hinter das erste logische Laufwerk, wo sich wiederum eine Partitionstabelle mit dem Eintrag für das nächste logische Laufwerk befindet. Die einzelnen Einträge der logischen Laufwerke sind also untereinander in einer einfach verketteten Liste verbunden. Der erste Sektor einer jeden primären oder erweiterten Partition enthält einen Boot-Sektor mit dem beschriebenen Aufbau. Da nur von einer dieser Partitionen gebootet werden kann, bestimmt das Bootflag die sog. aktive Partition. Der Code im MBR muss also a) die aktive Partition bestimmen, b) den Boot-Sektor der aktiven Partition mit Hilfe des BIOS laden und c) in den Boot-Sektor bei Offset 0 springen. Ein Bootloader wie LILO oder GRUB kan den MBR mit eigenem Code ersetzen oder den Boot-Sektor einer Partition belegen.

Wird der Bootloader (LILO oder GRUB) in den MBR installiert, so wird der Code dort ersetzt, d.h. der ehemalige MBR überschrieben. Wird der MBR dabei nicht automatisch gesichert, so sollte er zuvor mit

 $> dd if=/dev/hda of=MBR.backup bs=512 count=1
 

gesichert werden. Mit Hilfe von

 $> dd if=MBR.backup of=/dev/hda bs=446 count=1
 

wird der MBR ohne die Partitionstabelle zurückgeschrieben. Achtung: bei diesen Aktionen muss man sehr sorgfältig vorgehen, sonst können sämtliche Daten der Festplatte verloren sein. Soll die alte Partitionstabelle ebenfalls restauriert werden, so ist der Parameter bs=512 zu verwenden. Vorsicht: dabei kann man leicht seine Partitionstabelle zerstören.

Der Bootvorgang geht nun wie folgt vonstatten: Das BIOS selektiert das Gerät zum Booten. Dann wird der Boot-Sektor dieses Gerätes gelesen, in unserem Falle ist das der Boot-Sektor des Bootloaders auf der Festplatte. Dieser lädt das Setup, Dekompressionsroutinen und das komprimierte Kernel-Image in den Speicher. Ein mit "make bzImage" erstellter Kernel kann per BIOS Service "int 0x15" direkt vom niedrigen in den hohen Speicherbereich geladen werden (der Bootloader benutzt dazu die gleichen Techniken, wie sie auch im Kernel-eigenen Boot-Sektor enthalten sind). Nach dem Laden (ein Bootloader wie LILO beendet sich hier) wird arch/i386/boot/setup.S abgearbeitet und zum Eintrittspunkt start: gesprungen. Einige Hardware wird initialisiert und der Prozessor wird in den "Protected Mode" versetzt. Schließlich wird zum Anfang des eigentlichen komprimierten Kerns gesprungen, das entspricht arch/i386/boot/compressed/{head.S,misc.c}. Der Kernel wird nun entkomprimiert und die in arch/i386/boot/compressed/head.S aufgeführten Initialisierungen (z.B. Initialisierung der Page-Tabelle, des Coprozessors, des Stacks, usw.) finden statt. Dann wird start_kernel() aufgerufen. Hierdurch findet nun die "high level" Initialisierung statt, u.a.: architekturspezifisches Setup; Ausgabe des Linux Banner (Version des Kernels, Compiler, etc.); Initialisierung von IRQs, ACPI, Scheduler, Timer, etc.; Auswerten der Boot-Kommandozeile (Boot-Parameter); Initialisierung der Konsole und des dynamischen Ladens von Modulen; Interrupts werden ermöglicht; Ermittelung der BogoMIPS; Initialisierung des Speichermanagements und Ausgabe der Werte (Memory-Zeile); Initialisierung des Proc-Filesystems, diverser Caches und des Thread-Handlings; Auswerten architekturspezifischer Bugs und Aktivierung von Workarounds (z.B. der berühmte CPU "f00f Bug"). Letztendlich wird ein Kernel-Thread init() kreiert, der sämtliche Treiber für die Hardware initialisiert und dann entweder das als Boot-Parameter übergebene Programm init= aufruft oder versucht, /sbin/init, /etc/init oder /bin/init (in dieser Reihenfolge) auszuführen. Falls keines der Programme gefunden wird, wird versucht, eine Rettungskonsole mit der Shell /bin/sh zu starten. Geht das ebenfalls nicht, so tritt ein Kernel-Panic auf. Ansonsten geht das Booten dann mit der Abarbeitung wie in "man init" beschrieben weiter. Es werden normalerweise die unter Linux laufenden Hintergrundprozesse gestartet und dafür gesorgt, dass auf jedem angeschlossenen Terminal das Programm getty läuft. Ein Anwender kann sich dann beim System anmelden.

Der Bootvorgang ist hier nicht komplett und vollständig wiedergegeben, das würde schlicht den Rahmen dieses Textes sprengen. In der Praxis ist es weitaus komplizierter, da z.B. die Verwendung einer Initial Ramdisk oder Multiprozessor-Systeme berücksichtigt werden müssen. Man erhält aber schon in dieser vereinfachten Darstellung einen kleinen Einblick in die Komplexität und die Vorgänge, die im Hintergrund ablaufen.

Zurück zum Anfang des Textes

Der Linux-Kernel: wie alles begann

Linus Torvalds, ein finnischer Student in Helsinki, startete 1991 ein kleines neues Betriebssystem:

From:       torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
Newsgroups: comp.os.minix
Subject: What would you like to see most in minix?
Date: 25 Aug 91 20:57:08 GMT

Hello everybody out there using minix -
I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I'd like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things).

I've currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I'll get something practical within a few months, and I'd like to know what features most people would want. Any suggestions are welcome, but I won't promise I'll implement them :-)

Linus (torvalds@kruuna.helsinki.fi)

PS. Yes - it's free of any minix code, and it has a multi-threaded fs. It is NOT protable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that's all I have :-(.

Sein kleines Projekt fand sehr großen Anklang. Es bildete sich schnell eine Gruppe von Aktivisten, die die Entwicklung des neuen Betriebssystems vorantrieben. Zahlreiche Nutzer testen neue Versionen und tragen dazu bei, die Software von Fehlern zu bereinigen. Linux wird unter offenen und verteilten Bedingungen entwickelt. Mit "offen" ist gemeint, dass jeder, der dazu in der Lage ist, sich an der Entwicklung beteiligen kann. Daher ist eine schnelle, effektive und weltweite Kommunikation notwendig: das Internet. Es ist deswegen nicht verwunderlich, dass ein großer Teil der Entwicklungen von Studenten stammen, die an ihren Universitäten auf das Internet zugreifen können. Diesen Studenten standen anfangs Entwicklungssysteme mit eher bescheidener Ausstattung zur Verfügung, weswegen Linux auch immer noch das 32-Bit Betriebssystem ist, das die wenigsten Ressourcen verbraucht, ohne an Funktionalität einzubüßen. Linux läuft mittlerweile auf fast allem, was Bits und Bytes verarbeiten kann. Die unterstützte Hardware reicht von Embedded-Systemen bis hin zu IBM-Mainframes. Diese Hardwareunabhängigkeit wird von keinem anderen Betriebssystem erreicht.

Die rasante Entwicklung von Linux zeigt sich auch sehr beeindruckend an der Größe der Linux Kernel-Quellen:

Das entspricht einem exponentiellen Wachstum und man kann sich ausdenken, was das für zukünftige Kernel bedeutet :-) Das Ziel, die meiste GNU Software auf Linux zum Laufen zu bekommen, war übrigens bereits mit Version 0.99 realisiert.

Zurück zum Anfang des Textes

Links

Hier einige Links zu Literatur über den Linux-Kernel oder sonstigen Hilfen. Diese Liste ist sicherlich nicht vollständig, sollte aber für eine weitere Informationssuche ausreichen. Bitte beachten: die meiste Literatur zum Linux-Kernel ist in englisch verfasst.

Zurück zum Anfang des Textes

Danksagung

Ich (TH) danke den zahlreichen Ideengebern, die mich einerseits zum Schreiben dieser Anleitung animiert und andererseits dabei unterstützt haben. Insbesondere geht der Dank an Andreas Winkelmann für seine Hilfe beim Verfassen des Textes zum Bootloader GRUB, an Philipp Thomas, der mir einige Details zu den SUSE-Kerneln mitgeteilt hat, an David Haller, der mit seinem Multi-Kernel Howto das Fundament der ersten Version dieses Howtos gebildet hat, und an Jan Engelhardt, der dieses Howto verbessert und überarbeitet und damit auf den neusten Stand gebracht hat. Ferner haben Sebastian Huber, Klaus Ondrich, David Hundenborn, Hans-Robert Wagner, Horst Graffy und Guido Nottebrok (sowie einige leider anonyme Personen) mit ihrem Feedback dazu beigetragen, dieses Howto weiter zu verbessern. Ein ganz besonderes Dankeschön geht an Luigi di Lazzaro, der dieses Howto in die italienische Sprache übersetzt hat!

Zurück zum Anfang des Textes

Disclaimer

Dieser Text erhebt natürlich keinen Anspruch auf Richtigkeit und Vollständigkeit und natürlich wird keine Gewähr für alle Angaben oder daraus entstehender Konsequenzen übernommen. Der Vollständigkeit halber:

There is no warranty for this text. The author provides it 'as is', without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality of this text is with you. In no event will any author named in this text be liable to you for damages, including any general, special, incidental or consequential damages arising out of any use of this text (including, but not limited to, loss of data, data being rendered inaccurate, or losses sustained by anyone as a result of using this text).

Vielleicht mögen manche Leute gewisse Dinge hier anders sehen, aber dennoch hoffe ich, dass der Grundgedanke derselbe ist und ich hier auch keine all zu großen Bugs eingebaut habe. Wie steht schon sinngemäß im SUSE-Handbuch: Dieser Text entstand im Laufe vieler Stunden. Es bleibt nicht aus, dass im Verlaufe dieser Zeit bessere und weniger gute Abschnitte entstanden. Auch wenn ich eine Menge Fehler beseitigen konnte, so möchte ich doch den Eindruck vermeiden, es handele sich um ein fertiges Produkt. Die dicken Fehler sind nur besser versteckt ;-) Vielleicht habe ich ja die Chance, es beim nächsten Mal besser zu machen. Verbesserungsvorschläge, Korrekturhinweise, Lob und Kritik sind daher stets erwünscht und willkommen.

Dr. Thomas Hertweck ()
Jan Engelhardt ()