Kapitel 18. Weiterführende Themen

18.1. Wie kann ich mehr über die Interna von FreeBSD erfahren?
18.2. Wie kann ich bei der Entwicklung von FreeBSD mitarbeiten?
18.3. Was sind Snapshots und RELEASEs?
18.4. Wie kann ich meine eigene, angepasstes Release erstellen?
18.5. Wieso überschreibt make world das installierte System?
18.6. Warum ist cvsup.FreeBSD.org kein Round-Robin-Eintrag im DNS, so dass Anfragen auf alle CVsup-Server verteilt werden?
18.7. Kann ich -CURRENT mit begrenztem Internetzugang folgen?
18.8. Wie haben Sie die Distribution in 1392 KB-Dateien aufgespalten?
18.9. Ich habe eine Kernelerweiterung geschrieben. An wen sende ich sie?
18.10. Wie werden Plug&Play ISA-Karten erkannt und initialisiert?
18.11. Wie bekomme ich eine Major-Number für einen Gerätetreiber, den ich geschrieben habe?
18.12. Gibt es alternative Layoutverfahren für Verzeichnisse?
18.13. Wie kann ich optimalen Nutzen aus einer kernel panic ziehen?
18.14. Wieso funktioniert dlsym() nicht mehr für ELF-Executables?
18.15. Wie kann ich den Adressraum des Kernels auf i386 vergrössern oder verkleinern?

18.1. Wie kann ich mehr über die Interna von FreeBSD erfahren?

Zurzeit gibt es nur ein Buch über die Interna von FreeBSD, “The Design and Implementation of the FreeBSD Operating System” von Marshall Kirk McKusick und George V. Neville-Neil, ISBN 0-201-70245-2, das sich auf FreeBSD 5.X konzentriert.

Allgemeines Wissen über UNIX® kann allerdings in den meisten Fällen auf FreeBSD angewendet werden.

Eine Liste finden Sie im entsprechenden Abschnitt der Bibliographie.

18.2. Wie kann ich bei der Entwicklung von FreeBSD mitarbeiten?

Genauere Informationen finden Sie im Artikel FreeBSD unterstützen. Wir können Hilfe immer gut gebrauchen!

18.3. Was sind Snapshots und RELEASEs?

Derzeit existieren vier aktive/halbaktive Zweige im FreeBSD-CVS-Repository. In früheren Zweigen ändert sich wenig, daher gibt es nur vier aktive Entwicklungszweige:

  • RELENG_7 bzw. 7-STABLE

  • RELENG_8 bzw. 8-STABLE

  • RELENG_9 bzw. 9-STABLE

  • HEAD bzw. -CURRENT oder 10-CURRENT

HEAD ist keine wirkliche Bezeichnung für einen Zweig, wie die anderen. Es ist lediglich eine symbolische Konstante für “den aktuellen, nicht verzweigten Entwicklungsstrom”, auf den wir uns einfach als -CURRENT beziehen.

Derzeit steht -CURRENT für den 10.X-Entwicklungsstrom. Der 9-STABLE-Zweig (RELENG_9) wurde von -CURRENT im September 2011 und der 8-STABLE-Zweig (RELENG_8) im August 2009 von -CURRENT abgespalten.

18.4. Wie kann ich meine eigene, angepasstes Release erstellen?

Eine Anleitung dazu finden Sie im Artikel FreeBSD Release Engineering.

18.5. Wieso überschreibt make world das installierte System?

Das ist beabsichtigt. Wie der Name schon andeutet, erstellt make world alle Systemdateien von Grund auf neu. Sie können also sicher sein, am Ende eine saubere, konsistente Umgebung zu haben (das ist der Grund, warum es so lange dauert).

Falls die Umgebungsvariable DESTDIR während der Ausführung von make world oder make install definiert ist, werden die neu erstellten Binaries unter ${DESTDIR} in einem zum installierten identischen Verzeichnisbaum abgelegt. Einige zufällige Kombinationen von Änderungen von Shared Libraries und Neuerstellungen von Programmen können hierbei jedoch ein Scheitern von make world verursachen.

18.6. Warum ist cvsup.FreeBSD.org kein Round-Robin-Eintrag im DNS, so dass Anfragen auf alle CVsup-Server verteilt werden?

Die CVsup-Server gleichen sich stündlich mit dem Hauptserver ab. Allerdings findet der Abgleich nicht zur gleichen Zeit statt, daher können einige Server neuere Quellen bereitstellen als andere Server. Alle Server stellen jedoch Quellen bereit, die maximal eine Stunde alt sind. Wäre cvsup.FreeBSD.org ein Round-Robin-Eintrag im DNS, der Benutzern einen zufälligen Server zuteilt, könnten beim zweiten Lauf von CVsup ältere Quellen als beim ersten Lauf heruntergeladen werden.

18.7. Kann ich -CURRENT mit begrenztem Internetzugang folgen?

Ja, Sie können das tun, ohne den gesamten Quellbaum herunterzuladen, indem Sie die Einrichtung CTM benutzen.

18.8. Wie haben Sie die Distribution in 1392 KB-Dateien aufgespalten?

Bei neueren BSD-basierten Systemen gibt es eine Option -b zu split(1), die das Splitten von Dateien an willkürlichen Bytegrenzen erlaubt.

Hier ist ein Beispiel aus /usr/src/release/Makefile.

ZIPNSPLIT=              gzip --no-name -9 -c | split -b 1392k -

18.9. Ich habe eine Kernelerweiterung geschrieben. An wen sende ich sie?

Lesen Sie bitte den Artikel FreeBSD unterstützen.

Und Danke, dass Sie darüber nachdenken!

18.10. Wie werden Plug&Play ISA-Karten erkannt und initialisiert?

Von: Frank Durda IV

Kurz gesagt gibt es nur wenige I/O-Ports über die PnP-Karten antworten, wenn der Host fragt, ob jemand da ist. Wenn die PnP-Erkennungsroutine startet, fragt sie, ob irgendwelche PnP-Karten vorhanden sind und alle PnP-Karten antworten mit ihrer Modellnummer auf demselben Port, von dem sie auch gelesen haben. Die Erkennungsroutine erhält also ein geodertes “Ja” auf diese Frage. Mindestens ein Bit wird bei dieser Antwort gesetzt sein. Die Erkennungsroutine ist dann in der Lage, dafür zu sorgen, dass Karten mit Modellnummern (zugeordnet von Microsoft®/Intel®) kleiner als X “off-line” gesetzt werden. Sie prüft dann, ob immer noch Karten da sind, die auf die Frage antworten. Falls die Antwort 0 war, sind keine Karten mit IDs größer X vorhanden. Die Erkennungsroutine wird daraufhin anfragen, ob Karten unterhalb X vorhanden sind. Schließlich setzt die Erkennungsroutine alle Karten größer als X - (limit / 4) off-line und wiederholt die Frage. Wenn diese halbbinäre Suche nach IDs in Folge genügend oft wiederholt worden ist, wird die Erkennungsroutine schließlich alle in einem Rechner befindlichen PnP-Karten identifiziert haben und das mit einer Iterationszahl sehr viel kleiner als 264.

Die IDs bestehen aus zwei 32-Bit-Feldern (daher 264) + acht Bit Prüfsumme. Die ersten 32 Bit sind die Herstellerkennung. Es wurde zwar nicht bestätigt, aber es wird angenommen, dass unterschiedliche Kartentypen desselben Herstellers unterschiedliche 32-Bit Herstellerkennungen besitzen können. 32 Bit nur für eindeutige Hersteller zu benötigen, scheint etwas übertrieben.

Die niedrigen 32 Bit sind eine Seriennummer oder etwas anderes, das die betreffende Karte einzigartig macht. Die Hersteller dürfen niemals eine zweite Karte mit denselben niedrigen 32 Bit herstellen, es sei denn, die höheren 32 Bit sind unterschiedlich. Sie können also mehrere Karten des selben Typs im Rechner haben und die gesamten 64 Bit bleiben stets eindeutig.

Die 32-Bit-Gruppen können niemals nur aus Nullen bestehen. Das erlaubt es, bei der binären Suche zu Beginn nur auf von Null verschiedene Bits zu achten.

Wenn das System alle vorhandenen Karten-IDs identifiziert hat, reaktiviert es jede Karte - eine nach der anderen (über dieselben I/O-Ports) und ermittelt, welche Ressourcen von der jeweiligen Karte benötigt werden, welche Wahlmöglichkeiten für Interrupts bestehen usw. Alle Karten werden abgefragt, um diese Informationen zusammenzustellen.

Diese Informationen werden dann mit Informationen aus allen ECU-Dateien auf der Festplatte oder mit im MLB-BIOS verdrahteten Informationen verknüpft. Die ECU- und BIOS-PnP-Unterstützung für Hardware auf dem MLB ist für gewöhnlich künstlich und was die Peripheriegeräte tun ist nicht wirklich echtes PnP. Durch die Untersuchung der BIOS-Informationen und der ECU-Informationen können die Erkennungsroutinen jedoch die von PnP-Geräten benutzten Ressourcen so ändern, dass vermieden wird, dass bereits von anderen Geräten benutzte Ressourcen verwendet werden.

Dann werden die PnP-Geräte nochmals besucht und ihre I/O, DMA, IRQ und Memory-Map-Adressen werden zugeordnet. Die Geräte werden an diesen Stellen sichtbar werden und dort bis zum nächsten Reboot verbleiben. Allerdings hindert Sie auch nichts daran, sie zu verschieben, wohin Sie wollen.

Im obigen Teil wurde sehr viel vereinfacht, aber die grundlegende Idee sollte klar geworden sein.

Microsoft hat einige der primären Druckerstatusports für PnP übernommen, da keine Karte diese Adressen für die entgegengesetzten I/O-Zyklen decodiert. Ich habe während der frühen Überprüfungsperiode des PnP-Vorschlags eine echte IBM Druckerkarte gefunden, die Schreibzugriffe auf dem Statusport decodiert hat, aber Microsoft hat nur “tough” gesagt. Also schreiben sie auf den Druckerstatusport, um Adressen zu setzen, benutzen zusätzlich diese Adresse + 0x800 und einen dritten I/O-Port zum Lesen, der irgendwo zwischen 0x200 und 0x3ff liegen kann.

18.11. Wie bekomme ich eine Major-Number für einen Gerätetreiber, den ich geschrieben habe?

FreeBSD Versionen stellen seit Februar 2003 Major-Numbers für Geräte automatisch zur Laufzeit bereit (lesen Sie devfs(5)), damit ist das nicht mehr nötig.

18.12. Gibt es alternative Layoutverfahren für Verzeichnisse?

Als Antwort auf die Frage nach alternativen Layoutverfahren für Verzeichnisse ist das Schema, das derzeit benutzt wird, unverändert von dem, das ich 1983 geschrieben habe. Ich habe das Vorgehen für das originale Fast-Filesystem geschrieben und es niemals überarbeitet. Es funktioniert gut, wenn es darum geht, zu verhindern, dass Zylindergruppen volllaufen. Wie viele von Ihnen angemerkt haben, funktioniert es schlecht für find. Die meisten Dateisysteme werden von Archiven erstellt, die mit einer Tiefensuche (also ftw) erstellt wurden. Diese Verzeichnisse werden über die Zylindergruppen hinweg entfaltet und erzeugen denkbar ungünstigste Voraussetzungen für zukünftige Tiefensuchen. Falls man die Gesamtzahl der zu erstellenden Verzeichnisse wüsste, wäre die Lösung die, (gesamt / fs_ncg) pro Zylindergruppe zu erstellen, bevor fortgefahren wird. Offensichtlich müsste man eine Heuristik erstellen, um die Zahl zu schätzen. Sogar die Benutzung einer kleinen, fixen Zahl, z.B. 10, würde eine Verbesserung um Größenordnungen ausmachen. Um Wiederherstellungen von normalem Betrieb (wo der derzeitige Algorithmus vermutlich sinnvoller ist) zu unterscheiden, könnten Sie die Clusterung von bis zu 10 benutzen, wenn sie alle innerhalb eines 10-Sekunden-Fensters durchgeführt würden. Jedenfalls ist mein Schluss, dass dies ein fruchtbares Gebiet für Experimente ist.

Kirk McKusick , September 1998

18.13. Wie kann ich optimalen Nutzen aus einer kernel panic ziehen?

Hier ist eine typische Kernel-Panic

Fatal trap 12: page fault while in kernel mode

fault virtual address   = 0x40
fault code              = supervisor read, page not present
instruction pointer     = 0x8:0xf014a7e5
stack pointer           = 0x10:0xf4ed6f24
frame pointer           = 0x10:0xf4ed6f28
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, def32 1, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 80 (mount)
interrupt mask          =
trap number             = 12
panic: page fault

Wenn Sie eine Meldung wie diese sehen, reicht es nicht, sie einfach zu reproduzieren und sie einzusenden. Der Wert des Instruktionszeigers ist wichtig; leider ist er auch konfigurationsabhängig. Mit anderen Worten variieren die Werte abhängig von dem Kernel-Image, das Sie tatsächlich benutzen. Wenn Sie ein GENERIC Kernelimage von einem der Snapshots benutzen, dann ist es für jemand anderen möglich, die fehlerhafte Instruktion herauszufinden, aber wenn Sie einen angepassten Kernel benutzen, können nur Sie uns sagen, wo der Fehler auftrat.

Was Sie tun sollten, ist folgendes:

  1. Notieren Sie sich den Wert des Instruktionszeigers. Beachten Sie, dass der Teil 0x8: am Anfang in diesem Fall nicht von Bedeutung ist; der Teil 0xf0xxxxxx ist der, den wir wollen.

  2. Tun Sie folgendes, wenn das System rebootet:

    % nm -n /kernel.that.caused.the.panic | grep f0xxxxxx
    

    wobei 0xf0xxxxxx der Wert des Instruktionszeigers ist. Es besteht die Möglichkeit, dass Sie keinen exakten Treffer erzielen, weil die Symbole in der Symboltabelle des Kernels Funktionseinstiegspunkte sind und die Adresse des Instruktionszeigers irgendwo innerhalb einer Funktion liegen wird und nicht am Anfang. Falls sie keinen exakten Treffer erzielen, lassen Sie den letzten Teil des Werts des Instruktionszeigers weg und versuchen es noch einmal, z.B.:

    % nm -n /kernel.that.caused.the.panic | grep f0xxxxx
    

    Falls das kein Ergebnis liefert, hacken Sie eine weitere Ziffer ab. Wiederholen Sie die Schritte, bis Sie irgendeine Ausgabe erhalten. Das Ergebnis wird eine Liste möglicher Funktionen sein, die die Panik verursacht haben. Das ist zwar kein absolut genauer Mechanismus, um die Fehlerursache ausfindig zu machen, aber es ist besser als gar nichts.

Wie dem auch sei, der beste Weg, den Grund für eine Panik herauszufinden, ist der, einen Crash-Dump festzuhalten und dann kgdb(1) zu benutzen, um den Stack im Crash-Dump zurückzuverfolgen.

Jedenfalls ist die Methode, die ich normalerweise benutze, folgende:

  1. Sorgen Sie dafür, dass die folgende Zeile in der Kernelkonfigurationsdatei (/usr/src/sys/arch/conf/MYKERNEL) enthalten ist:

    makeoptions     DEBUG=-g          # Build kernel with gdb(1) debug symbols
    
  2. Wechseln Sie in das Verzeichnis usr/src:

    # cd /usr/src
    
  3. Erstellen Sie den Kernel:

    # make buildkernel KERNCONF=MYKERNEL
    
  4. Warten Sie, bis make(1) den Kernel fertig kompiliert hat.

  5. # make installkernel KERNCONF=MYKERNEL
    
  6. Starten Sie das System neu.

Anmerkung: Falls Sie die make-Variable KERNCONF nicht verwenden, wird ein GENERIC Kernel gebaut und installiert.

Der make(1)-Prozess wird zwei Kernel erstellt haben: /usr/obj/usr/src/sys/MYKERNEL/kernel und /usr/obj/usr/src/sys/MYKERNEL/kernel.debug. kernel wurde als /boot/kernel installiert, während kernel.debug als Quelle für Debuggersymbole für kgdb(1) benutzt werden kann.

Um sicherzustellen, dass ein Crash-Dump erhalten bleibt, müssen Sie /etc/rc.config editieren und dumpdev so setzen, dass es auf Ihre Swap-Partition zeigt. Das bewirkt, dass die rc(8)-Skripte den Befehl dumpon(8) benutzen, um Crash-Dumps zu ermöglichen. Sie können dumpon(8) auch manuell ausführen. Nach einer Panik kann der Crash-Dump mit savecore(8) wiederhergestellt werden; wenn dumpdev in /etc/rc.conf gesetzt ist, werden die rc(8)-Skripte savecore(8) automatisch ausführen und den Crash-Dump unter /var/crash ablegen.

Anmerkung: Crash-Dumps von FreeBSD sind für gewöhnlich genauso groß wie der physikalische Hauptspeicher Ihres Rechners. Das heißt, wenn Sie 512MB RAM haben, werden sie einen 512MB Crash-Dump erhalten. Deshalb müssen Sie dafür sorgen, dass genügend Speicherplatz in /var/crash zur Verfügung steht, um den Dump aufnehmen zu können. Alternativ führen Sie savecore(8) manuell aus und lassen es den Crash-Dump in einem anderen Verzeichnis wiederherstellen, in dem Sie mehr Platz haben. Es ist möglich, die Größe des Crash-Dumps zu begrenzen, indem options MAXMEM=N, wobei N die Größe des verwendeten Kernelspeichers in KBs ist. Wenn Sie z.B. 1 GB RAM haben, können Sie die Speicherbenutzung des Kernels damit auf 128 MB begrenzen, so dass die Größe Ihres Crash-Dumps 128 MB anstatt 1 GB betragen wird.

Wenn Sie den Crash-Dump wiederhergestellt haben, können Sie den Stack mit kgdb(1) so zurückverfolgen:

% kgdb /usr/obj/usr/src/sys/MYKERNEL/kernel.debug /var/crash/vmcore.0
(kgdb) backtrace

Beachten Sie, dass es mehrere Seiten mit wertvollen Informationen geben könnte; idealerweise sollten Sie script(1) benutzen, um sie alle festzuhalten. Wenn Sie das vollständige Kernelimage mit allen Debugginginformationen benutzen, müssten Sie exakt die Zeile des Kernel-Sourcecodes finden, wo die Panik aufgetreten ist. Für gewöhnlich müssen Sie den Stack von unten an zurückverfolgen, um die genaue Ereignisabfolge, die zum Crash führte, zurückzuverfolgen. Sie können kgdb(1) auch zum Ausdrucken der Inhalte verschiedener Variablen oder Strukturen benutzen, um den Systemstatus zum Zeitpunkt des Absturzes zu untersuchen.

Tipp: Wenn Sie nun wirklich verrückt sind und einen zweiten Computer haben, können Sie kgdb(1) auch für entferntes Debugging konfigurieren, so dass Sie kgdb(1) auf einem System benutzen können, um den Kernel auf einem anderen System zu debuggen, einschließlich dem Setzen von Haltepunkten und dem Bewegen in Einzelschritten durch den Kernelcode, genauso, wie Sie es mit einem normalen Benutzerprogramm tun können.

Anmerkung: Wenn Sie DDB aktiviert haben und der Kernel im Debugger landet, können Sie eine Panik (und einen Crash-Dump) erzwingen, indem Sie einfach panic am ddb-Prompt eingeben. Er könnte während der Panikphase wieder im Debugger stoppen. Falls er das tut, geben Sie continue ein, dann wird er den Crash-Dump beenden.

18.14. Wieso funktioniert dlsym() nicht mehr für ELF-Executables?

Die ELF-Werkzeuge machen die in einem Executable definierten Symbole dem dynamischen Linker nicht standardmäßig sichtbar. Konsequenterweise werden dlsym()-Suchen nach Handlern aus Aufrufen von dlopen(NULL, flags) diese Symbole nicht finden können.

Wenn Sie mit dlsym() nach im Hauptexecutable eines Prozesses vorhandenen Symbolen suchen wollen, müssen Sie das Executable mit der Option --export-dynamic von ld(1) linken.

18.15. Wie kann ich den Adressraum des Kernels auf i386 vergrössern oder verkleinern?

Standardmäßig beträgt der Adressraum des Kernels 1 GB (2 GB für PAE) auf i386. Wenn Sie einen netzwerkintensiven Server (z.B. einen großen FTP- oder HTTP-Server) betreiben, oder ZFS verwenden möchten, kann es sein, dass Sie der Meinung sind, dass das nicht ausreichen.

Fügen Sie die folgende Zeile zu ihrer Kernelkonfigurationsdatei hinzu, um den verfügbaren Speicher zu erhöhen und erstellen Sie dann einen neuen Kernel:

options KVA_PAGES=N

Um den richtigen Wert von N zu bestimmen, teilen Sie den gewünschte Größe des Addressraumes (in Megabyte) durch vier (z.B. beträgt er 512 für 2 GB).

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <[email protected]>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <[email protected]>.