Früher Userspace bei Arch Linux
Atsutane, 13.02.2010 - 20:00
Dieser Eintrag ist eine Übersetzung von brain0s Early Userspace in Arch Linux für jene Arch Linux Nutzer, welche mit dem Englischen dann doch ihre Probleme haben, keine Gewähr auf Fehlerfreiheit. Dieser Eintrag unterliegt nicht der im Impressum angegebenen Lizenz, die Rechte liegen bei Thomas Bächler, die Übersetzung ist mit seinem Einverständnis erfolgt.
In letzter Zeit gab es einige große Änderungen bei Archs Programmen des fühen Userspace. Also dachte ich mir, dass ich mir die Zeit nehme und allen diese Änderungen erläutere.
Bootvorgang von Linuxsystemen: Wofür braucht man einen frühen Userspace?
Früher war das starten eines Linux Systems einfach: Der bootloader lud den Kernel, dieser wurde extrahiert und initialisierte die Hardware, danach initialisierte er den Festplatten-Controller, erkannte die Festplatte und das sich darauf befindliche Root-Dateisystem, band dieses ein uns startete /sbin/init.
Heutzutage gibt es eine gigantische Menge an unterschiedlichen Controllern und eine große Anzahl unterschiedlicher Dateisysteme, da wir eine ordentliche Distribution sind möchten wir alle unterstützen. Also bauen wir sie alle in unser monolithisches Kernelimage welches nun mehrere Megabyte groß ist alles bis zur Küchenspüle unterstützt, aber dann kommt jemand und hat zwei SATA-Controller, drei IDE-Controller, sieben Festplatten sowie drei externe USB-Laufwerke und wer weiß was. Der Kernel erkennt diese nun alle asynchron, aber wo ist nun bitte das Root-Dateisystem? Ist es auf der ersten Festplatte? Oder auf der dritten? Was ist "die erste Festplatte" überhaupt? Und wie binde ich mein Root-Dateisystem in der LVM Laufwerksgruppe im verschlüsselten Container auf dem Software RAID-Array ein? Wie man sieht wird das alles etwas hässlich und der Kernel stellt sich gerne dumm oder kümmert sich einfach nicht um diese nervtötenden Probleme, besonders nachdem er durch uns - die wir ihn mit jeden erdenklichen Treiber gefüttert haben - so fett wurde.
Was nun? Ganz einfach, wir übergeben die Kontrolle dem Userspace und regeln die Erkennung der Hardware dort, richten den ganzen komplizierten und von den Leuten gewünschten Kram ein, binden das Root-Dateisystem ein und starten /sbin/init selbst. Nun frägst du dich sicherlich "Wie führe ich Applikationen im Userspace aus, wenn das Root-Dateisystem nicht eingebunden ist?" die Antwort darauf lautet "Magie!".
Was ist initramfs?
Naja die Antwort ist nicht Magie. Die Antwort lautet eigentlich initramfs: Jedes Linux System hat ein ramfs Dateisystem, welches immer eingebunden ist und rootfs heißt. Wahrscheinlich wirst du dieses nie sehen, da deine wirklichen Dateisysteme es nach dem Einbinden überdecken. Allerdings führt der Kernel auch ein komprimiertes cpio Archiv mit sich, welches direkt nach dem Start in das rootfs extrahiert wird. Noch besser: Es ist sogar möglich aus dem Bootloader heraus ein solches Archiv an den Kernel anzuhängen, welches dann ebenfalls in das rootfs entpackt wird.
Bevor der Kernel den altmodischen init Code ausführt, prüft er, ob das rootfs eine Datei namens /init enthält, ist dies der Fall überspringt er den klassischen Einbindungs- und Initcode und führt stattdessen /init aus. Nun liegt die Verantwortung für diese Aufgabe, welche für den Kernel als zu kompliziert eingeschätzt wird, bei diesem Programm. Auf diese Weise können wir einen Kernel, welcher keinerlei eingebaute Unterstützung für einen Festplatten-Controller auch nur für irgendein Dateisystem bietet(das ist eigentlich, was wir mit dem Arch Linux Standardkernel machen) bauen und fügen die benötigten Module schlichtweg in das initramfs Image ein.
klibc - Das Fegefeuer für die Initramfs Maintainer
klibc wurde ursprünglich als kleine leichtgewichtige C Bibliothek für den frühen Userspace entwickelt. Sie bringt einige Programme mit, welche einem dabei helfen alles Einzurichten. Mit klcc führt sie sogar ein hässliches Perlskript mit, welches den gcc aufruft und Binärdateien gegen die klibc anstatt die übliche libc linkt. Als Aaron Griffin 2006 mkinitcpio als Ersatz für die alten, unflexiblen Skripte mkinitrd und mkinitramfs entwickelte, wurde entschieden es auf klibc basieren zu lassen. Von Anfang an hatte klibc Probleme:
- Das Set an mitgelieferten Programmen war begrenzt und den Programmen fehlten wichtige Optionen.
- Die meisten externen Programme liesen sich nicht gegen die klibc linken oder mussten dafür stark gepatcht werden.
- Es gab keinen dynamischen Linker, alle Binärdateien wurden statisch gegen eine spezifische Version der klibc gelinkt, diese Version änderte sich mit jeder Änderung an den klibc Quellen oder der Kernelheader, was dann wieder den Neubau aller - gegen die klibc gelinkten - Binärdateien nötig machte.
- Es war nicht möglich andere dynamische Bibliotheken, als die klibc selbst zu erstellen.
Irgendwann war klibc inkompatibel zu den Kernelheadern und wir mussten mehr und mehr Hacks einführen um es aktualisieren zu können. Seit Linux 2.6.30 war ich nicht in der Lage überhaupt eine funktionierende Version der klibc zu bauen, was uns mit einer alten Binärdatei zurückließ, bei welcher wir nicht einmal mehr Bugs fixen konnten. Mitte 2009 starb dann upstream vollkommen, keine commits ins git Repository und acuh auf der Mailingliste gab es nur eine Hand voll Mails pro Monat. Das brachte mich dazu, mir folgende Frage zu stellen: "Worin besteht der Sinn eine seperate C Bibliothek zusammen mit Programmen zu verwalten, welche nur für den Bruchteil einer Sekunde beim Start des Systems Verwendung finden?" Außer einem kleineren initramfs Image und dadurch verkürzte Bootzeit vermutlich nichts.
Es einfach halten
2009 entschied ich dann, dass um eine initramfs Umgebung mit geringem Verwaltungsaufwand, vielen Funktionen und großer Flexibilität, die folgenenden Änderungen nötig waren:
- Verwendung der C Bibliothek des Systems und keiner seperaten.
- Die Verwendung von busybox für grundlegende System- und Skriptingprogramme, um einen guten Kompromiss ziwschen hoher Funktionalität und kleiner Dateigröße zu finden.
- Die Verwendung von util-linux-ngs blkid, um Label von Dateisystemen, UUID und Typerkennung vollständig für alle neuen und alten Dateisysteme zu haben.
- Die Verwendung von modprobe, udev, lvm, cryptsetup, mdadm/mdassemble aus den normalen Arch Paketen für weitere fortgeschrittene Funktionen.
Nun ist es Februar 2010 und in den letzten Wochen hatte ich endlich die Zeit, die ganze Arbeit zu erledigen. Erst vor wenigen Tagen veröffentlichte ich mkinitcpio 0.6, diese Version ist deutlich stabiler, flexibler und weniger fehleranfällig als jede klibc-basierte Version die wir je hatten. Das initramfs ist nun um Durchschnitt 600KB bis 1MB größer, ich glaube nicht, dass sich deswegen jemand beschwert, es ist immer noch kleiner als bei den meisten anderen Distributionen. Ich bin froh, dass ich hoffentlich nie wieder mit klibc zu tun haben werde.


Kommentare:
mirabilos - 25.03.2010 - 22:46
Nimm doch uClibc… ggf. sogar mit mksh zusammen (die übrigens auch auf einer nur leicht gepatchten klibc baut), da gibts ordentliches Skripting und gute interaktive Funktionalität.¥¥µ
Hinterlasse selbst einen Kommentar: