Linux Dateisystem Aufbau: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
 
(2 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
==Interna '''Unix''' Dateisysteme==
+
==Verwaltungsdaten und Nutzdaten==
*Generell werden die Verwaltungsinformationen von den eigentlichen Daten getrennt.  
+
 
*Die Verwaltungsdaten werden in so genannten Inodes gehalten, deren vereinfachten Aufbau diese Abbildung zeigt.
+
*In allen klassischen Unix-Dateisystemen werden die Verwaltungsinformationen streng von den Nutzdaten getrennt.
*Jede Datei (und das gilt für jeden Dateityp) wird durch genau einen Inode repräsentiert.
+
*Die Verwaltungsdaten stehen in den so genannten '''Inodes''' (Index Nodes).
*Innerhalb einer Partition besitzt jeder Inode eine eindeutige Nummer.
+
*Jede Datei wird durch genau einen Inode repräsentiert – und das gilt für jeden Dateityp: reguläre Datei, Verzeichnis, Symlink, Gerätedatei, FIFO und Socket.
 +
*Innerhalb eines Dateisystems besitzt jeder Inode eine eindeutige Nummer.
 +
*Die Anzahl der Inodes wird beim Anlegen des Dateisystems festgelegt und lässt sich später nicht mehr ändern. Ein Dateisystem kann also "voll" sein, obwohl noch Plattenplatz frei ist.
 +
 
 
{{#drawio:datsys-1}}
 
{{#drawio:datsys-1}}
 +
''Abbildung 1: Aufbau eines Inodes''
  
*Im Laufe der Installation wird auf jeder Partition ein Dateisystem angelegt.  
+
===Was im Inode steht===
*Alle'''Unix'''-Dateisysteme lassen sich in das in dieser Abbildung skizzierte Schema einordnen
+
 
 +
{| class="wikitable"
 +
! Feld !! Bedeutung
 +
|-
 +
| Dateityp || regulär, Verzeichnis, Symlink, Block-/Zeichengerät, FIFO, Socket
 +
|-
 +
| Zugriffsrechte || die klassischen Mode-Bits inklusive SUID, SGID und Sticky Bit
 +
|-
 +
| UID / GID || Besitzer und Gruppe, gespeichert als Zahl, nicht als Name
 +
|-
 +
| Link Count || Anzahl der Namen, die auf diesen Inode zeigen
 +
|-
 +
| Größe || Dateigröße in Byte
 +
|-
 +
| Zeitstempel || atime (letzter Zugriff), mtime (letzte Inhaltsänderung), ctime (letzte Inode-Änderung)
 +
|-
 +
| belegte Blöcke || in Einheiten zu 512 Byte, unabhängig von der Blockgröße des Dateisystems
 +
|-
 +
| i_block || 15 Zeiger zu je 4 Byte, zusammen 60 Byte
 +
|}
 +
 
 +
===Was nicht im Inode steht===
 +
 
 +
*'''Die Inode-Nummer selbst.''' Sie ergibt sich aus der Position in der Inode-Tabelle und wird berechnet, nicht gespeichert.
 +
*'''Der Dateiname.''' Namen existieren ausschließlich in Verzeichnissen. Das ist der Grund dafür, dass Hardlinks überhaupt funktionieren.
 +
 
 +
$ ls -i brief.txt
 +
4711 brief.txt
 +
$ stat brief.txt
 +
 
 +
===Die 60 Byte im i_block===
 +
 
 +
*Die ersten 12 Zeiger verweisen direkt auf Datenblöcke. Bei 4 KiB Blockgröße sind damit Dateien bis 48 KiB ohne Umweg erreichbar.
 +
*Reicht das nicht, verweist der 13. Zeiger auf einen '''einfach indirekten Block''', der selbst nur Zeiger enthält (bei 4 KiB Blockgröße 1024 Stück).
 +
*Der 14. und 15. Zeiger arbeiten zweifach beziehungsweise dreifach indirekt.
 +
 
 +
'''Achtung, häufiger Irrtum:''' Kleine Dateien werden ''nicht'' im Inode selbst abgelegt. Die 60 Byte des Zeiger-Arrays nutzt nur ein Symlink, dessen Ziel höchstens 59 Zeichen lang ist (siehe unten). Eine reguläre Datei bekommt immer mindestens einen eigenen Datenblock. Erst ext4 kann mit dem optionalen Feature <code>inline_data</code> und 256-Byte-Inodes kleine Dateiinhalte im Inode halten – das ist aber nicht die Voreinstellung.
 +
 
 +
==Verzeichnisse, Hardlinks und Symlinks==
 +
 
 +
*Ein Verzeichnis ist selbst nur eine Datei. Ihr Inhalt ist eine Tabelle aus Dateinamen und der jeweils zugehörigen Inode-Nummer.
 +
*Ein Datenblock lässt aus Sicht des Systems keinen Rückschluss auf den zugehörigen Inode zu – der Weg führt immer vom Namen über den Inode zu den Daten, nie zurück.
 +
 
 +
{{#drawio:datsys-5}}
 +
''Abbildung 2: Verzeichniseintrag, Inode und Datenblöcke''
 +
 
 +
===Hardlink===
 +
 
 +
*Ein Hardlink ist ein zusätzlicher Name für denselben Inode. Es gibt kein Original und keine Kopie – beide Namen sind gleichwertig.
 +
*Jeder Name erhöht den Link Count.
 +
*<code>rm</code> löscht keine Datei, sondern einen Verzeichniseintrag. Die Datenblöcke werden erst freigegeben, wenn der Link Count 0 erreicht ''und'' kein Prozess die Datei mehr geöffnet hat.
 +
*Hardlinks funktionieren nur innerhalb eines Dateisystems, weil Inode-Nummern nur dort eindeutig sind.
 +
 
 +
$ ln brief.txt zweitname.txt
 +
$ ls -li brief.txt zweitname.txt
 +
$ find / -inum 4711
 +
 
 +
===Symlink===
 +
 
 +
*Ein Symlink ist eine eigene Datei mit eigenem Inode. Sein Inhalt ist der Zielpfad als Text.
 +
*Ist der Zielpfad höchstens 59 Zeichen lang, wird er direkt in den 60 Byte des Zeiger-Arrays abgelegt. Man spricht von einem '''Fast Symlink''' – er belegt keinen einzigen Datenblock.
 +
*Der Pfad wird bei jedem Zugriff neu aufgelöst. Verschwindet das Ziel, zeigt der Symlink ins Leere.
 +
 
 +
$ ln -s brief.txt verweis.txt
 +
$ stat verweis.txt          # Blocks: 0
 +
$ readlink verweis.txt
  
 
==Anfang der Partition==
 
==Anfang der Partition==
 +
 
{{#drawio:datsys-2}}
 
{{#drawio:datsys-2}}
===Erläuterung===
+
''Abbildung 3: Grundschema eines Unix-Dateisystems''
{| Border=1 Cellpadding=2
+
 
|Bootblock
+
{| class="wikitable"
|Der erste Block jeder Partition kann einen Bootloader (zum Start eines Betriebssystems) enthalten, er wird beim Einschalten des Rechners vom BIOS gelesen. Dieser Block existiert bei allen Dateisystemen.
+
! Bereich !! Bedeutung
 +
|-
 +
| Bootblock
 +
| Die ersten 1024 Byte einer ext-Partition bleiben für einen Bootloader reserviert. Historisch stammt das aus der Zeit, als das BIOS den MBR der Platte einlas und von dort weiterverzweigte. Bei UEFI wird stattdessen die EFI System Partition (FAT32) gelesen und ein <code>.efi</code>-Programm geladen – der reservierte Bereich am Partitionsanfang wird dann gar nicht mehr benutzt, bleibt aber bestehen.
 
|-
 
|-
|Superblock
+
| Superblock
|Hier stehen Informationen zum Typ und internen Aufbau des Dateisystems. Der Inhalt ist also systemabhängig
+
| Beginnt bei Offset 1024 Byte und ist selbst 1024 Byte groß. Er enthält Typ und internen Aufbau des Dateisystems: Anzahl der Inodes und Datenblöcke (gesamt und frei), Blockgröße, Inode-Größe, Zeitpunkt des letzten Mountens, Zähler der Mountvorgänge, Status und Zeitpunkt der letzten Prüfung sowie die aktivierten Features.
 
|-
 
|-
|Inode-Blöcke
+
| Inode-Blöcke
|Inodes werden innerhalb der Filesysteme in Inode-Listen geführt, und sind definierte Datenstrukturen, die eine Datei eindeutig beschreiben und verwalten können.  
+
| Die Inode-Tabelle. Inodes liegen hier hintereinander, jeder mit fester Größe. Aus der Nummer lässt sich damit die Position direkt berechnen.
Im einfachsten Fall stehen alle Inodes hintereinander auf der Platte.
 
Ist die Datei sehr klein (<= 60 Bytes), werden ihre Daten direkt im Inode
 
gespeichert, ansonsten verweist ein Eintrag im Inode auf einen (oder
 
mehrere) Datenblock, in dem nun der Inhalt der Datei gespeichert wird.
 
Reichen die in einem Inode referenzierten Blöcke (maximal 12) für eine
 
Datei nicht aus, zeigt ein Eintrag im Inode auf einen (oder mehrere)
 
Datenblock, welcher nun die eigentlichen Verweise zu den Datenblöcken
 
beinhaltet. Man spricht von einem einfach indirekten Block.
 
Bis zu dreifach indirekte Blöcke sind möglich, so dass theoretisch als
 
maximale Dateigröße 8 TByte bei einer Blockgröße von 4 KByte erzielt
 
werden ( [ 12 + 1024 + 1024*1024 + 1024*1024*1024 ] * 4 kb ). Durch
 
weitere Faktoren auf 32 Bit Architekturen ist dieser Wert bei Kernel 2.2
 
allerdings auf 2 GByte begrenz
 
 
|-
 
|-
|Datenblöcke
+
| Datenblöcke
|Gehört ein Block zu einer normalen Datei, dann stehen hier die Daten zu dieser. Gehört der Block zu einem Verzeichniseintrag, so enthält er den
+
| Der eigentliche Nutzdatenbereich – in der Praxis über 95 Prozent der Partition.
Inhalt des Verzeichnisses, also eine Tabelle aus Dateinamen und
 
zugehöriger Inode. Ein Datenblock lässt (aus Sicht des Systems) keinen
 
Rückschluss auf den zugehörigen Inode zu.
 
Da die Blockgröße festliegt, wird im Falle, dass die Dateigröße diese
 
nicht erreicht, Plattenplatz verschwendet. In Anbetracht der
 
durchschnittlichen Dateigrößen in einem Unix-System hat sich 4096
 
Byte als optimale Blockgröße herausgestellt. Wählt man einen kleineren
 
Wert, erhöht sich zwar die mittlere Auslastung der einzelnen Blöcke,
 
allerdings benötigt man ggf. mehr indirekte Datenblöcke (sowie im
 
konkreten Falle des Linux-Dateisystems größere Bitmaps).
 
 
|}
 
|}
  
==Optimierungen im '''Linux'''-Dateisystem==
+
===Blockgröße===
  
Schauen wir uns nun die Einteilung einer Partition im ext2 an:
+
*Die Blockgröße wird beim Anlegen festgelegt, üblich sind 4096 Byte.
 +
*Da immer ganze Blöcke belegt werden, verschwendet jede Datei im Schnitt einen halben Block ('''interne Fragmentierung'''). Bei 4 KiB Blockgröße und einer Datei von 100 Byte bleiben 3996 Byte ungenutzt.
 +
*Eine kleinere Blockgröße erhöht die Ausnutzung der einzelnen Blöcke, benötigt dafür aber mehr Zeiger, mehr indirekte Blöcke und größere Bitmaps.
  
{{#drawio:datsys-3}}
+
==Optimierungen im Linux-Dateisystem==
  
 +
Auf den ersten Blick hat ext2 keine Ähnlichkeit mit dem klassischen Unix-Schema. Abgesehen vom Bootblock, über den verfügt bekanntlich jedes Dateisystem. Aber das täuscht: Die Partition wird lediglich in '''Blockgruppen''' zerlegt, und in jeder Gruppe findet sich das bekannte Schema wieder.
  
Scheinbar besitzt das ext2 keinerlei Änlichkeit mit herkömmlichen Unix-
+
{{#drawio:datsys-4}}
Dateisystemen. Abgesehen vom Bootblock, aber über diesen verfügt bekanntlich
+
''Abbildung 4: Aufteilung in Blockgruppen und Struktur einer Gruppe''
jedes Dateisystem. Aber das täuscht... Vergleichen wir einmal die Struktur einer
 
Gruppe mit dem Unix-Prinzip:
 
  
{{#drawio:datsys-4}}
+
{| class="wikitable"
 +
! Bereich !! Bedeutung
 +
|-
 +
| Superblock
 +
| Eine Sicherheitskopie des Superblocks aus Gruppe 0. Damit lässt sich ein zerstörter primärer Superblock ersetzen.
 +
|-
 +
| Gruppen-Deskriptoren
 +
| Enthalten die Verwaltungsinformationen zu allen Gruppen des Dateisystems: wo Bitmaps und Inode-Tabelle jeder Gruppe liegen und wie viele Inodes und Blöcke frei sind.
 +
|-
 +
| Block-Bitmap
 +
| Ein Bit je Datenblock der Gruppe, belegt oder frei. Die Bitmap ist genau einen Block groß und begrenzt damit die Gruppengröße: bei 4096 Byte sind das 32768 Blöcke, also 128 MiB.
 +
|-
 +
| Inode-Bitmap
 +
| Ein Bit je Inode der Gruppe.
 +
|-
 +
| Inode-Tabelle
 +
| Die Inodes dieser Gruppe.
 +
|-
 +
| Datenblöcke
 +
| Der Nutzdatenbereich der Gruppe.
 +
|}
 +
 
 +
*Der Sinn der Gruppen ist Lokalität: Verwaltungsdaten und die dazugehörigen Nutzdaten liegen dicht beieinander, die Kopfbewegungen bleiben kurz.
 +
*Fällt in einer Gruppe die Verwaltungsinformation aus, lässt sie sich aus den Kopien der anderen Gruppen rekonstruieren – genau davon lebt <code>fsck</code>.
 +
 
 +
===Was sich bei ext4 geändert hat===
 +
 
 +
*'''sparse_super''': Superblock-Kopien liegen nicht mehr in jeder Gruppe, sondern nur in Gruppe 0, Gruppe 1 sowie in allen Gruppen, deren Nummer eine Potenz von 3, 5 oder 7 ist. Der Satz "in jeder Gruppe steht eine Kopie" gilt also für aktuelle Dateisysteme nicht mehr.
 +
*'''flex_bg''': Bitmaps und Inode-Tabellen mehrerer Gruppen (voreingestellt 16) werden zusammengezogen und hintereinander abgelegt. Dadurch entstehen große zusammenhängende freie Bereiche für die Nutzdaten.
 +
*'''Inode-Größe''': voreingestellt 256 Byte statt 128 Byte. Der zusätzliche Platz nimmt Zeitstempel in Nanosekunden, die Erzeugungszeit (crtime) und erweiterte Attribute auf.
 +
 
 +
# dumpe2fs -h /dev/vg0/daten
 +
# dumpe2fs /dev/vg0/daten | grep -i superblock
 +
# tune2fs -l /dev/vg0/daten | grep -i 'inode size'
 +
 
 +
==ext4: Extents statt Zeigerkaskade==
 +
 
 +
Die Zeigerkaskade aus Abbildung 1 ist der eigentliche Schwachpunkt von ext2 und ext3: Für jeden einzelnen Datenblock wird ein Zeiger gebraucht. ext4 belegt dieselben 60 Byte im Inode anders und beschreibt zusammenhängende Bereiche als '''Extent''' – mit logischem Startblock, physischem Startblock und Länge.
 +
 
 +
{{#drawio:datsys-6}}
 +
''Abbildung 5: Indirekte Blöcke gegenüber Extents''
 +
 
 +
*Vier Extents passen direkt in den Inode. Reicht das nicht, verweist der Extent-Header auf einen '''Extent-Baum''' (B-Baum).
 +
*Ein Extent fasst bis zu 32768 Blöcke, bei 4 KiB Blockgröße also 128 MiB am Stück.
 +
*Eine große, unfragmentierte Datei kommt damit mit einer Handvoll Einträge aus, wo ext3 zehntausende Zeiger gebraucht hätte.
  
Abbildung: Struktur einer ext2-Gruppe
+
$ filefrag -v grossedatei.img
  
Superblock, Inode-Tabelle und Datenblöcke sind hier enthalten.
+
===Maximale Größen===
  
{| Border=1 Cellpadding=2
+
{| class="wikitable"
|Superblock
+
! Dateisystem !! Blockgröße !! max. Dateigröße !! max. Dateisystem
|Die Superblöcke der einzelnen Gruppen sind exakte Kopien
 
des Superblockes aus Gruppe 0. Er enthält in einer 1024
 
Bytes großen Struktur alle wichtigen Informationen zum
 
Dateisystem, wie die Anzahl von Inodes und Datenblöcken
 
(gesamt/frei), Blockgröße der Datenblöcke (ein Inode ist
 
immer 128 Byte groß), Zeitpunkt des letzten Mountens,
 
Zähler der Anzahl der Mountvorgänge, Status, Zeit der
 
letzten Überprüfung usw.
 
|-
 
|Gruppendeskriptoren
 
|Hier wurde zusätzliche Sicherheit eingebaut. Die
 
Deskriptoren enthalten alle notwendigen Informationen zu
 
allen anderen Gruppen, um diese nach einem Defekt
 
restaurieren zu können. Sind in einer Gruppe also die
 
Verwaltungsinformationen (Superblock,
 
Gruppendeskriptoren oder Bitmaps) zerstört worden, können
 
diese repariert werden und die Daten sind weiterhin
 
verfügbar
 
 
|-
 
|-
|Bitmaps
+
| ext2 / ext3 || 4 KiB || 2 TiB || 16 TiB
|Sie dienen dem schnellen Auffinden von freien
 
Inode/Datenblöcken. Ihre Größe entspricht der
 
Datenblockgröße und beschränkt die Anzahl der
 
Datenblöcke einer Gruppe (bei einer Blockgröße von 4096
 
Bytes sind es somit 32768).
 
 
|-
 
|-
|Inodetabelle/Datenblöcke
+
| ext4 || 4 KiB || 16 TiB || 1 EiB (mit Feature <code>64bit</code>)
|Hier gilt das schon in der allgemeinen Beschreibung gesagte.
 
 
|}
 
|}
 +
 +
Die häufig genannte Rechnung für die Zeigerkaskade lautet:
 +
 +
( 12 + 1024 + 1024^2 + 1024^3 ) x 4 KiB = ca. 4 TiB
 +
 +
Das ist der rechnerische Wert. Praktisch bleibt ext3 bei 2 TiB, weil Blocknummern nur 32 Bit breit sind und die Belegung in 512-Byte-Einheiten geführt wird.
 +
 +
==Praxis: nachsehen statt glauben==
 +
 +
Inode-Nummer und Metadaten einer Datei:
 +
 +
$ ls -li datei
 +
$ stat datei
 +
 +
Aufbau des Dateisystems (als root):
 +
 +
# dumpe2fs -h /dev/sdaX
 +
# tune2fs -l /dev/sdaX
 +
 +
Belegung von Blöcken und Inodes:
 +
 +
$ df -h
 +
$ df -i
 +
 +
Verteilung der Datenblöcke einer Datei:
 +
 +
$ filefrag -v datei
 +
 +
Einen Inode direkt ansehen (als root):
 +
 +
# debugfs -R "stat <4711>" /dev/sdaX
 +
 +
==Ausblick: btrfs==
 +
 +
btrfs bricht mit dem hier gezeigten Aufbau:
 +
 +
*Es gibt keine feste Inode-Tabelle mehr. Metadaten liegen in B-Bäumen und wachsen dynamisch mit.
 +
*'''Copy on Write''': Geänderte Blöcke werden nicht überschrieben, sondern neu geschrieben. Erst danach wird der Verweis umgehängt.
 +
*Daraus folgen Snapshots und Subvolumes fast von selbst – ein Snapshot ist nur ein zweiter Verweis auf denselben Baum.
 +
*Prüfsummen über Metadaten und Nutzdaten erkennen stille Datenfehler, die ext4 nicht bemerkt.

Aktuelle Version vom 19. August 2026, 15:56 Uhr

Verwaltungsdaten und Nutzdaten

  • In allen klassischen Unix-Dateisystemen werden die Verwaltungsinformationen streng von den Nutzdaten getrennt.
  • Die Verwaltungsdaten stehen in den so genannten Inodes (Index Nodes).
  • Jede Datei wird durch genau einen Inode repräsentiert – und das gilt für jeden Dateityp: reguläre Datei, Verzeichnis, Symlink, Gerätedatei, FIFO und Socket.
  • Innerhalb eines Dateisystems besitzt jeder Inode eine eindeutige Nummer.
  • Die Anzahl der Inodes wird beim Anlegen des Dateisystems festgelegt und lässt sich später nicht mehr ändern. Ein Dateisystem kann also "voll" sein, obwohl noch Plattenplatz frei ist.

Abbildung 1: Aufbau eines Inodes

Was im Inode steht

Feld Bedeutung
Dateityp regulär, Verzeichnis, Symlink, Block-/Zeichengerät, FIFO, Socket
Zugriffsrechte die klassischen Mode-Bits inklusive SUID, SGID und Sticky Bit
UID / GID Besitzer und Gruppe, gespeichert als Zahl, nicht als Name
Link Count Anzahl der Namen, die auf diesen Inode zeigen
Größe Dateigröße in Byte
Zeitstempel atime (letzter Zugriff), mtime (letzte Inhaltsänderung), ctime (letzte Inode-Änderung)
belegte Blöcke in Einheiten zu 512 Byte, unabhängig von der Blockgröße des Dateisystems
i_block 15 Zeiger zu je 4 Byte, zusammen 60 Byte

Was nicht im Inode steht

  • Die Inode-Nummer selbst. Sie ergibt sich aus der Position in der Inode-Tabelle und wird berechnet, nicht gespeichert.
  • Der Dateiname. Namen existieren ausschließlich in Verzeichnissen. Das ist der Grund dafür, dass Hardlinks überhaupt funktionieren.
$ ls -i brief.txt
4711 brief.txt
$ stat brief.txt

Die 60 Byte im i_block

  • Die ersten 12 Zeiger verweisen direkt auf Datenblöcke. Bei 4 KiB Blockgröße sind damit Dateien bis 48 KiB ohne Umweg erreichbar.
  • Reicht das nicht, verweist der 13. Zeiger auf einen einfach indirekten Block, der selbst nur Zeiger enthält (bei 4 KiB Blockgröße 1024 Stück).
  • Der 14. und 15. Zeiger arbeiten zweifach beziehungsweise dreifach indirekt.

Achtung, häufiger Irrtum: Kleine Dateien werden nicht im Inode selbst abgelegt. Die 60 Byte des Zeiger-Arrays nutzt nur ein Symlink, dessen Ziel höchstens 59 Zeichen lang ist (siehe unten). Eine reguläre Datei bekommt immer mindestens einen eigenen Datenblock. Erst ext4 kann mit dem optionalen Feature inline_data und 256-Byte-Inodes kleine Dateiinhalte im Inode halten – das ist aber nicht die Voreinstellung.

Verzeichnisse, Hardlinks und Symlinks

  • Ein Verzeichnis ist selbst nur eine Datei. Ihr Inhalt ist eine Tabelle aus Dateinamen und der jeweils zugehörigen Inode-Nummer.
  • Ein Datenblock lässt aus Sicht des Systems keinen Rückschluss auf den zugehörigen Inode zu – der Weg führt immer vom Namen über den Inode zu den Daten, nie zurück.

Abbildung 2: Verzeichniseintrag, Inode und Datenblöcke

Hardlink

  • Ein Hardlink ist ein zusätzlicher Name für denselben Inode. Es gibt kein Original und keine Kopie – beide Namen sind gleichwertig.
  • Jeder Name erhöht den Link Count.
  • rm löscht keine Datei, sondern einen Verzeichniseintrag. Die Datenblöcke werden erst freigegeben, wenn der Link Count 0 erreicht und kein Prozess die Datei mehr geöffnet hat.
  • Hardlinks funktionieren nur innerhalb eines Dateisystems, weil Inode-Nummern nur dort eindeutig sind.
$ ln brief.txt zweitname.txt
$ ls -li brief.txt zweitname.txt
$ find / -inum 4711

Symlink

  • Ein Symlink ist eine eigene Datei mit eigenem Inode. Sein Inhalt ist der Zielpfad als Text.
  • Ist der Zielpfad höchstens 59 Zeichen lang, wird er direkt in den 60 Byte des Zeiger-Arrays abgelegt. Man spricht von einem Fast Symlink – er belegt keinen einzigen Datenblock.
  • Der Pfad wird bei jedem Zugriff neu aufgelöst. Verschwindet das Ziel, zeigt der Symlink ins Leere.
$ ln -s brief.txt verweis.txt
$ stat verweis.txt          # Blocks: 0
$ readlink verweis.txt

Anfang der Partition

Abbildung 3: Grundschema eines Unix-Dateisystems

Bereich Bedeutung
Bootblock Die ersten 1024 Byte einer ext-Partition bleiben für einen Bootloader reserviert. Historisch stammt das aus der Zeit, als das BIOS den MBR der Platte einlas und von dort weiterverzweigte. Bei UEFI wird stattdessen die EFI System Partition (FAT32) gelesen und ein .efi-Programm geladen – der reservierte Bereich am Partitionsanfang wird dann gar nicht mehr benutzt, bleibt aber bestehen.
Superblock Beginnt bei Offset 1024 Byte und ist selbst 1024 Byte groß. Er enthält Typ und internen Aufbau des Dateisystems: Anzahl der Inodes und Datenblöcke (gesamt und frei), Blockgröße, Inode-Größe, Zeitpunkt des letzten Mountens, Zähler der Mountvorgänge, Status und Zeitpunkt der letzten Prüfung sowie die aktivierten Features.
Inode-Blöcke Die Inode-Tabelle. Inodes liegen hier hintereinander, jeder mit fester Größe. Aus der Nummer lässt sich damit die Position direkt berechnen.
Datenblöcke Der eigentliche Nutzdatenbereich – in der Praxis über 95 Prozent der Partition.

Blockgröße

  • Die Blockgröße wird beim Anlegen festgelegt, üblich sind 4096 Byte.
  • Da immer ganze Blöcke belegt werden, verschwendet jede Datei im Schnitt einen halben Block (interne Fragmentierung). Bei 4 KiB Blockgröße und einer Datei von 100 Byte bleiben 3996 Byte ungenutzt.
  • Eine kleinere Blockgröße erhöht die Ausnutzung der einzelnen Blöcke, benötigt dafür aber mehr Zeiger, mehr indirekte Blöcke und größere Bitmaps.

Optimierungen im Linux-Dateisystem

Auf den ersten Blick hat ext2 keine Ähnlichkeit mit dem klassischen Unix-Schema. Abgesehen vom Bootblock, über den verfügt bekanntlich jedes Dateisystem. Aber das täuscht: Die Partition wird lediglich in Blockgruppen zerlegt, und in jeder Gruppe findet sich das bekannte Schema wieder.

Abbildung 4: Aufteilung in Blockgruppen und Struktur einer Gruppe

Bereich Bedeutung
Superblock Eine Sicherheitskopie des Superblocks aus Gruppe 0. Damit lässt sich ein zerstörter primärer Superblock ersetzen.
Gruppen-Deskriptoren Enthalten die Verwaltungsinformationen zu allen Gruppen des Dateisystems: wo Bitmaps und Inode-Tabelle jeder Gruppe liegen und wie viele Inodes und Blöcke frei sind.
Block-Bitmap Ein Bit je Datenblock der Gruppe, belegt oder frei. Die Bitmap ist genau einen Block groß und begrenzt damit die Gruppengröße: bei 4096 Byte sind das 32768 Blöcke, also 128 MiB.
Inode-Bitmap Ein Bit je Inode der Gruppe.
Inode-Tabelle Die Inodes dieser Gruppe.
Datenblöcke Der Nutzdatenbereich der Gruppe.
  • Der Sinn der Gruppen ist Lokalität: Verwaltungsdaten und die dazugehörigen Nutzdaten liegen dicht beieinander, die Kopfbewegungen bleiben kurz.
  • Fällt in einer Gruppe die Verwaltungsinformation aus, lässt sie sich aus den Kopien der anderen Gruppen rekonstruieren – genau davon lebt fsck.

Was sich bei ext4 geändert hat

  • sparse_super: Superblock-Kopien liegen nicht mehr in jeder Gruppe, sondern nur in Gruppe 0, Gruppe 1 sowie in allen Gruppen, deren Nummer eine Potenz von 3, 5 oder 7 ist. Der Satz "in jeder Gruppe steht eine Kopie" gilt also für aktuelle Dateisysteme nicht mehr.
  • flex_bg: Bitmaps und Inode-Tabellen mehrerer Gruppen (voreingestellt 16) werden zusammengezogen und hintereinander abgelegt. Dadurch entstehen große zusammenhängende freie Bereiche für die Nutzdaten.
  • Inode-Größe: voreingestellt 256 Byte statt 128 Byte. Der zusätzliche Platz nimmt Zeitstempel in Nanosekunden, die Erzeugungszeit (crtime) und erweiterte Attribute auf.
# dumpe2fs -h /dev/vg0/daten
# dumpe2fs /dev/vg0/daten | grep -i superblock
# tune2fs -l /dev/vg0/daten | grep -i 'inode size'

ext4: Extents statt Zeigerkaskade

Die Zeigerkaskade aus Abbildung 1 ist der eigentliche Schwachpunkt von ext2 und ext3: Für jeden einzelnen Datenblock wird ein Zeiger gebraucht. ext4 belegt dieselben 60 Byte im Inode anders und beschreibt zusammenhängende Bereiche als Extent – mit logischem Startblock, physischem Startblock und Länge.

Abbildung 5: Indirekte Blöcke gegenüber Extents

  • Vier Extents passen direkt in den Inode. Reicht das nicht, verweist der Extent-Header auf einen Extent-Baum (B-Baum).
  • Ein Extent fasst bis zu 32768 Blöcke, bei 4 KiB Blockgröße also 128 MiB am Stück.
  • Eine große, unfragmentierte Datei kommt damit mit einer Handvoll Einträge aus, wo ext3 zehntausende Zeiger gebraucht hätte.
$ filefrag -v grossedatei.img

Maximale Größen

Dateisystem Blockgröße max. Dateigröße max. Dateisystem
ext2 / ext3 4 KiB 2 TiB 16 TiB
ext4 4 KiB 16 TiB 1 EiB (mit Feature 64bit)

Die häufig genannte Rechnung für die Zeigerkaskade lautet:

( 12 + 1024 + 1024^2 + 1024^3 ) x 4 KiB = ca. 4 TiB

Das ist der rechnerische Wert. Praktisch bleibt ext3 bei 2 TiB, weil Blocknummern nur 32 Bit breit sind und die Belegung in 512-Byte-Einheiten geführt wird.

Praxis: nachsehen statt glauben

Inode-Nummer und Metadaten einer Datei:

$ ls -li datei
$ stat datei

Aufbau des Dateisystems (als root):

# dumpe2fs -h /dev/sdaX
# tune2fs -l /dev/sdaX

Belegung von Blöcken und Inodes:

$ df -h
$ df -i

Verteilung der Datenblöcke einer Datei:

$ filefrag -v datei

Einen Inode direkt ansehen (als root):

# debugfs -R "stat <4711>" /dev/sdaX

Ausblick: btrfs

btrfs bricht mit dem hier gezeigten Aufbau:

  • Es gibt keine feste Inode-Tabelle mehr. Metadaten liegen in B-Bäumen und wachsen dynamisch mit.
  • Copy on Write: Geänderte Blöcke werden nicht überschrieben, sondern neu geschrieben. Erst danach wird der Verweis umgehängt.
  • Daraus folgen Snapshots und Subvolumes fast von selbst – ein Snapshot ist nur ein zweiter Verweis auf denselben Baum.
  • Prüfsummen über Metadaten und Nutzdaten erkennen stille Datenfehler, die ext4 nicht bemerkt.