Das Linux-Dateisystem Ext4

Seite 3: Weitere Optimierungen

Inhaltsverzeichnis

Weitere Optimierungen im Dateisystem sorgen dafür, dass Ext4 Dateien auch unabhängig von der „persistent preallocation“ möglichst am Stück speichert. Schreibzugriffe werden zunächst gepuffert, sodass der Block Allocator, der in Ext3 und Ext4 Datenblöcke für Schreiboperationen reserviert, nicht mehr für jeden 4-KByte-Block Daten sofort aufgerufen werden muss („delayed allocation“), sondern mehrere Blöcke auf einmal allozieren kann. Dadurch lassen sich bei größeren Schreibzugriffen viele Blöcke auf einmal und idealerweise als ein Extent am Stück belegen („multiblock allocation“).

Diese Änderungen verringern den Overhead im Dateisystem und damit sowohl die Systemlast als auch I/O-Engpässe, wenn eine Anwendung größere Mengen Daten schreibt, und verhindern die Fragmentierung von Dateien. Nur für kurze Zeit angelegte temporäre Dateien können komplett im Cache bleiben und werden gar nicht erst auf die Platte geschrieben. Beim Mounten von Ext4 erzeugt der Ext4-Code eine Liste freier Extents für jede Blockgruppe, die im Speicher bleibt und mit deren Hilfe der Block Allocator die Verteilung der Dateien auf der Platte optimiert.

Die „delayed allocation“ ist allerdings eine sehr aggressive Caching-Strategie, die das Risiko von Datenverlusten bei einem Systemabsturz oder Stromausfall erhöht. Nicht nur, dass die Daten länger im Cache bleiben – „delayed allocation“ entkoppelt auch das Schreiben von Daten und Metadaten: Eine neu angelegte Datei kann im Dateisystem bereits auftauchen, bevor die Daten auf die Platte geschrieben sind. Sie hat dann eine Größe von 0 Byte und keine zugeordneten Datenblocks, bis die Daten tatsächlich auf der Platte gelandet sind.

Das hat einen hässlichen Nebeneffekt bei Anwendungen, die beim Überschreiben einer existierenden Datei mit neuen Daten besonders vorsichtig sind: Viele Programmierer schreiben in diesem Fall die neuen Daten zunächst in eine temporäre Datei, die sie dann mit rename() auf den alten Namen umbenennen. Die Logik dahinter: Solange die neuen Daten noch nicht geschrieben sind, bleibt zumindest die alte Version der Datei erhalten.

Mit der „delayed allocation“ kann es allerdings passieren, dass die überschriebene Datei nach einem Systemabsturz gar keine Daten mehr enthält, da der Eintrag im Dateisystem auf die neue, bereits angelegte, aber noch nicht mit Daten befüllte Datei zeigt – rename() ist eine reine Metadaten-Operation. Das Gleiche kann passieren, wenn die Anwendung vor dem Schreiben der neuen Daten ftruncate() aufruft: Das Abschneiden der alten Datei passiert viel schneller als das Schreiben der neuen Daten.

Dieses Verhalten von Ext4 ist durchaus konform mit dem POSIX-Standard und tritt auch bei anderen Dateisystemen, etwa XFS, auf. Ext3 allerdings verhält sich hier in seinem Standard-Betriebsmodus „data=ordered“ gutmütiger und nimmt Änderungen an den Metadaten erst vor, wenn die Daten auf die Platte geschrieben sind – was aber keine bewusste Design-Entscheidung, sondern eher Zufall ist. Dennoch verlassen sich mittlerweile zahlreiche Linux-Anwendungen darauf.

Das „0-Byte-Problem“ hat zu hitzigen Diskussionen unter den Kernel-Entwicklern geführt, wobei zwei sehr unterschiedliche Sichtweisen aufeinandergeprallt sind: Die der Dateisystementwickler, denen es um maximale Performance und die Sicherstellung eines in sich konsistenten Dateisystems geht, und der eher pragmatische Blick beispielsweise von Linus Torvalds, nach dessen Ansicht das Dateisystem den Erwartungen der Anwender gerecht werden sollte – und die wollen vor allem keinen Datenverlust. Mit dem kommenden Kernel 2.6.30 versucht Ext4, problematische Situationen zu erkennen und sich dort wie Ext3 zu verhalten, also die Daten zu schreiben, bevor die Metadaten geändert werden. Der Kernel 2.6.28 von Ubuntu 9.04 enthält bereits diese Patches – hier tritt das Problem also gar nicht auf.

Zusätzlich zu der optimierten Allozierungsstrategie, die eine Dateifragmentierung weitgehend verhindern kann, soll sich Ext4 auch im Betrieb defragmentieren lassen. Ein Defragmentier-Tool soll wahlweise einzelne Dateien oder ganze Dateisysteme defragmentieren, wobei das Programm nichts grundlegend Anderes macht, als die Daten umzukopieren. Wichtig ist das Werkzeug vor allem, wenn man ein bestehendes Ext3-Dateisystem nach Ext4 migrieren möchte, da es Ext3-mäßig gespeicherte Dateien in das Ext4-Format wandeln können soll. Derzeit sind allerdings weder die für die Online-Defragmentierung erforderlichen Patches in den Linux-Kernel integriert noch ist das Defragmentier-Tool fertiggestellt.

Einige Neuerungen sollen die Zuverlässigkeit des Dateisystems erhöhen. So versieht das Journal jede Transaktion mit einer Checksumme. Damit lassen sich nicht nur fehlerhaft ins Journal geschriebene Daten erkennen; zudem vereinfacht sich der Commit von abgeschlossenen Transaktionen im Journal. Auch in den Blockgruppendeskriptoren kommen Checksummen zum Einsatz.

Ext4 nutzt standardmäßig den Barriere-Mechanismus, den neuere Festplatten bieten. Eine solche Barriere beeinflusst das Caching und Umsortieren von Schreibzugriffen moderner Festplatten: Der Platten-Controller führt alle Schreibzugriffe vor einer Barriere aus, bevor er die Schreibzugriffe hinter der Barriere in Angriff nimmt. Damit lässt sich beispielsweise sicherstellen, dass alle zu einer Transaktion gehörenden Schreibvorgänge im Dateisystem ausgeführt sind, bevor der Commit ins Journal geschrieben wird. Mit der Mount-Option barriers=0 lässt sich dieser Mechanismus abschalten.

Die Extents erlauben in Ext4 umfangreichere Konsistenzchecks als die Blocklisten in Ext3. So lässt sich beispielsweise überprüfen, ob sich die Extents einer Datei überschneiden. Zudem speichern die Extent-Header in einem Extent-Baum die Baumtiefe, die über den gesamten Baum konsistent sein muss, und die einem Extent-Index zugeordneten Extents müssen denselben Bereich einer Datei abdecken wie der Index. Bei der indirekten Blockadressierung von Ext3 hingegen ist ein Block mit Blocknummern nicht von zufälligen Daten unterscheidbar, ein Konsistenzcheck daher nur sehr rudimentär möglich.

Sollte einmal ein kompletter fsck-Lauf notwendig sein, geht das bei Ext4 deutlich schneller als bei Ext3. Mit der Option uninit_bg (in Ubuntu 9.04 standardmäßig gesetzt) initialisiert mkfs.ext4 nicht alle Blockgruppen. Das beschleunigt nicht nur das Anlegen des Dateisystems, sondern sorgt vor allem dafür, dass e2fsck lediglich die initialisierten Inodes überprüfen muss. Die Dauer eines fsck-Laufs hängt damit nur noch von der Zahl der Dateien, nicht von der Zahl der insgesamt vorhandenen Inodes (und damit der Größe des Dateisystems) ab.

Mit Ext4 fallen einige Grenzen. So erlaubt das Dateisystem eine unbegrenzte Zahl von Unterverzeichnissen in einem Directory, bei Ext3 waren lediglich 32.000 erlaubt. Die Inodes haben jetzt standardmäßig eine Größe von 256 Byte, bei Ext3 reichten noch 128 Byte. Den zusätzlichen Platz nutzt Ext4 unter anderem dazu, die Zugriffszeiten statt in Sekunden in Nanosekunden zu protokollieren und extended attributes direkt im Inode zu speichern.

Ein Patch von Google-Entwicklern für den aktuellen Kernel 2.6.29 erlaubt es, Ext4 ohne Journal zu betreiben, was den Durchsatz nach Messungen von Google um bis zu zwei Prozent erhöhen kann. Angesichts der Vorteile, die das Journal im Fall eines Systemabsturzes oder Stromausfalls bringt, dürfte das allerdings nur dann ernsthaft in Frage kommen, wenn es wirklich auf jedes Quentchen I/O ankommt. Die Userland-Tools bieten derzeit noch keine Möglichkeit, den Betrieb ohne Journal einzurichten.

Auch wenn die Ext4-Entwickler gerne die Kompatibilität mit Ext3 herausstreichen, sind diese Aussagen doch mit Vorsicht zu genießen. Zwar lässt sich ein Ext3-Dateisystem als Ext4 mounten, Auswirkungen auf das Dateisystem hat das jedoch keine: Ext4 kennt noch das alte Ext3-Schema zur Blockadressierung und spricht das Dateisystem genauso wie Ext3 an. Man kann auf dem als Ext4 gemounteten Dateisystem lesen und schreiben und es anschließend wieder als Ext3 weiterverwenden.

Erst wenn man mit

tune2fs -O extents

bei Ext3 das Dateisystem-Feature extents setzt und damit die Extents aktiviert, behandelt der Ext4-Code das Dateisystem tatsächlich als Ext4. Die bereits existierenden Dateien bleiben allerdings unverändert im Ext3-Format gespeichert – ein Flag im Inode gibt ja an, ob der Inode Blocknummern oder Extents enthält. Lediglich Dateien, die nach der Umwandlung und dem Mounten als Ext4 neu angelegt werden, profitieren von den neuen Datenstrukturen.

Bei einer solchen Konvertierung entsteht also kein „echtes“ Ext4-Dateisystem, sondern ein Hybrid aus Ext3- und Ext4-Strukturen. Wer ein Dateisystem vollständig von Ext3 nach Ext4 migrieren möchte, kommt um das Sichern der Daten und Neuanlegen des Dateisystems nicht herum. Abhilfe könnte das bereits erwähnte Defragmentier-Tool bringen, das – auf unter Ext3 gespeicherte Dateien losgelassen – die defragmentierte Datei im Ext4-Format mit Extents anlegt.

Nach dem Setzen des extents-Features führt kein bequemer Weg mehr zu Ext3 zurück: Ebenso wie ein mit

mkfs -t ext4

gleich als Ext4 angelegtes Dateisystem lässt sich Ext4 nicht mehr als Ext3 mounten. Das kann beim Einsatz eines etwas älteren Rettungssystems ohne Ext4-Unterstützung für böse Überraschungen sorgen. (odi) (odi)