Open Source im professionellen Einsatz

Dateisysteme

Aktuell verwenden die meisten Distributionen ein Ext-4-Dateisystem, das nicht nur performant arbeitet, sondern auch besonders große Dateien ermöglicht. Mittelfristig wird aber wohl Btrfs die Rolle des Standardfilesystems übernehmen. Dann sollen auch Filesystemchecks bei einem gemounteten und in Verwendung befindlichen Dateisystem möglich sein. Die universelle Dateisystemschnittstelle ermöglicht es Linux, auf unterschiedlichste Dateisysteme zuzugreifen, wie etwa FAT, NTFS oder ISO9660.

Abbildung 6: Applikationen und Kernelthreads durchlaufen verschiedene Zustände.

Taskzustände

Tasks können sich in unterschiedlichen Zuständen befinden. Grundsätzlich erzeugt der Systemcall »clone()« eine neue Task als exakte Kopie ihres Elternprozesses. Der neue Job befindet sich im lauffähigen Zustand (»TASK_RUNNING« ). Der Scheduler wählt aus allen lauffähigen Jobs jenen aus, den die CPU als nächsten abarbeitet. Der so genannte Context-Switch aktiviert die Task, die sich damit im aktiven Zustand befindet. Es gibt diverse Gründe, warum sich eine Task selbst in den schlafenden Zustand versetzt: Sie wartet auf Daten, sie wartet auf ein Betriebsmittel oder will einfach nur Zeit verstreichen lassen.

Linux unterscheidet verschiedene Arten des Schlafens. In der einfachsten Variante schläft der Job exakt so lange, bis das Ende der Schlafensbedingung erreicht ist und niemand im Kernel die »wake_up« -Funktion aufruft. In diesem Zustand weckt den Job nichts anderes. Nicht gar so tief schläft der Job im Killable-Zustand. Hier kann ihn immerhin das Signal  9 (»SIGKILL« ) aufwecken. Den leichten Schlaf repräsentiert der Interruptible-Zustand. Hier wird der Job durch jedes Signal geweckt.

Selbstmord im Kernel

In Abbildung 6 ist gut zu erkennen, dass Jobs sich grundsätzlich selbst beenden. Die Aufforderung zum "Selbstmord" kann jedoch per Signal von anderen Jobs aus (per Systemcall »kill« ) erfolgen. Bevor aber sämtliche Spuren des Jobs erloschen sind, nimmt er noch den Zombie-Status an.

In diesem Zustand hat der Kernel zwar bereits die zum Prozess gehörenden Speicherbereiche (Code-, Daten- und Stacksegmente) freigegeben, der Task-Kontrollblock aber, die Datenstruktur, die den Job im Kernel repräsentiert, existiert noch. Bevor diese gelöscht wird, muss die Elterntask den Exitcode (Returnwert der Funktion »main« ) abholen. Ist die Elterntask bereits selbst beendet, übernimmt der Job mit der PID 1 (der Init-Prozess) dieses Abholen.

Außerdem lassen sich Daten auch in virtuellen Dateisystemen ablegen: Aus Sicht der Applikation gibt es Dateien, die real nur im Hauptspeicher und nicht auf der Festplatte zu finden sind. Mehr noch, die Daten entstehen erst beim Zugriff.

Drei virtuelle Dateisysteme kennen die meisten Admins: Das Proc-Filesystem enthält Informationen über sämtliche Rechenprozesse, das Sys-Filesystem über die Hardwarestruktur inklusive der zugehörigen Treiber. Das Temp-Filesystem schließlich ermöglicht die Ablage von Daten im Hauptspeicher, ohne dass überhaupt ein klassisches Dateisystem zum Zuge kommt. Das nutzt Linux, um per Initram-FS quasi ohne Treiber zu booten [5]. Außerdem ermöglicht ein VFS auch das Schichten von Dateisystemen, um damit beispielsweise einfach eine Verschlüsselung zu realisieren.

In enger Verbindung zum VFS stehen die Gerätetreiber, die den weitaus größten Teil des Linux-Quellcode stellen. Historisch wird ein Treiber über eine Major-Nummer identifiziert, die 8 Bit breit ist. Die sich daraus ergebende Anzahl von gerade einmal 256 Treibern ist für ein modernes Betriebssystem jedoch viel zu wenig. Linux arbeitet daher mit Gerätenummern, die insgesamt 32 Bit breit sind. Mit einer Kodierung von rund 4000 Treibern mit insgesamt 4 Milliarden anzusprechenden Geräten ist das ausreichend dimensioniert.

Abbildung 7: Da alle Page-Directories in den höchsten Adressen die gleichen Einträge aufweisen, ist beim Übergang in den Kernel kein Umschalten der Speicherbereiche notwendig.

Den größten Sprung von 2.6.0 zu 3.0 hat der Linux-Kernel im Bereich Echtzeitverhalten gemacht. Nicht zuletzt dank des deutschen Kernelentwicklers Thomas Gleixner, der seine Realtime-Patches in "schmackhafte, Trojanische Pferde" verpackt hat [6], stehen dem Architekten eines Echtzeitsystems mit Linux viele Möglichkeiten offen: Hochauflösende Timer (Hrtimer) erlauben sehr genaue Zeitsteuerungen, Realtime-Mutexe bieten Prioritätsvererbung und die bisher nicht erwähnten CPU-Sets fixieren Rechenprozesse exklusiv auf spezifischen Rechnerkernen eines Multicoresystems.

4G/4G-Patch

Auf einem 32-Bit-System sind Adressenregister 32 Bit breit und geben damit Zugriff auf 4 GByte virtuellen Hauptspeicher. Der Versuch einer Applikation, diesen Adressraum komplett zu nutzen und auf eine Adresse oberhalb von 3 GByte zuzugreifen, scheitert jedoch kläglich mit einem Segmentation Fault. Im Adressraum der Applikation haben die Kernelentwickler das oberste Gigabyte für den Kernel reserviert. Konkret: In dem Page-Directory einer jeden Task stehen in den höchsten Adressen exakt die gleichen Einträge, während die übrigen Einträge Task-spezifisch sind (Abbildung 7).

Dadurch kann der Kernel mit dem Page-Directory jeder gerade aktiven Task auf seine dort referenzierten Speicherbereiche – den Kernelspace – zugreifen. Ohne diesen Trick müsste Linux bei jedem Systemcall und bei jedem Interrupt das Page-Directory, also den Einsprung in die Speicherverwaltung, austauschen. Dazu gehörte dann auch das Leeren des Translation Lookaside Buffer (TLB), des Cache für die Speicherverwaltung. Das ist zeitlich betrachtet ein teurer Vorgang.

Sollte eine speicherhungrige Task doch den Bedarf nach 4 GByte virtuellem Speicher haben, kann der Admin das 4G/4G-Patch aktivieren, das dem Kernel ein eigenes Page-Directory zuweist. In einem solchen Fall sollte er allerdings vorzugsweise den Umstieg auf ein 64-Bit-System erwägen.

Hinzu kommen die erwähnten Techniken Threaded Interrupts, Kernel-Preemption und Tickless Kernel. Das unter Entwicklern berüchtigte Big Kernel Lock (BKL), das in den alten Versionen mal eben Interrupts auf sämtlichen Prozessoren gesperrt hat, ist ebenfalls rechtzeitig vor der Veröffentlichung von 3.0 aus dem Kernel verschwunden.

Code zum Anfassen

Der Linux-Kernel 3.0 präsentiert sich aus vielen Gründen als spannendes Stück produktiver Software. Nicht nur, weil er objektorientiert aufgebaut ist, ohne eine objektorientierte Programmiersprache zu verwenden, und weil er eine ungewöhnliche Skalierbarkeit und Portierbarkeit aufweist oder weil er die Ideen und die Programmierfähigkeiten unterschiedlichster, weltweit verstreuter Entwickler vereint, sondern auch, weil er dank seiner Open-Source-Lizenz ein Stück Hightech zum Anfassen ist.

Infos

  1. Linus Torvalds, "Linux 3.0-rc1": http://thread.gmane.org/gmane.linux.kernel/1147415
  2. Quade, Kunst, "Kern-Technik", Folge 33 (Multicore): Linux-Magazin 05/07, S. 52
  3. Quade, Kunst, "Linux-Treiber entwickeln", 3. Auflage: Dpunkt-Verlag, 2011, S 232 ff.
  4. Quade, Kunst, "Kern-Technik", Folge 23 (VFS): Linux-Magazin 10/05, S. 90
  5. Quade, Kunst, "Kern-Technik", Folge 39 (Tempfs): Linux-Magazin 05/08, S. 98
  6. Thomas Gleixner, "Forced threaded interrupt handlers": https://lkml.org/lkml/2011/2/23/510

Der Autor

Eva-Katharina Kunst, Journalistin, und Jürgen Quade, Professor an der Hochschule Niederrhein, sind seit den Anfängen von Linux Fans von Open Source. Mittlerweile ist die dritte Auflage ihres Buches "Linux Treiber entwickeln" erschienen.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 6 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook