Linux Dateisystem Aufbau: Unterschied zwischen den Versionen
| (9 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
| − | == | + | ==Verwaltungsdaten und Nutzdaten== |
| − | * | + | |
| − | *Die Verwaltungsdaten | + | *In allen klassischen Unix-Dateisystemen werden die Verwaltungsinformationen streng von den Nutzdaten getrennt. |
| − | *Jede Datei | + | *Die Verwaltungsdaten stehen in den so genannten '''Inodes''' (Index Nodes). |
| − | *Innerhalb | + | *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'' | ||
| + | |||
| + | ===Was im Inode steht=== | ||
| + | |||
| + | {| 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}} | ||
| + | ''Abbildung 3: Grundschema eines Unix-Dateisystems'' | ||
| − | {| | + | {| class="wikitable" |
| − | |Bootblock | + | ! 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 |
| − | | | + | | 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 |
| − | | | + | | 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 | + | | 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. | |
| − | |||
| − | jedes Dateisystem. Aber das täuscht. | ||
| − | |||
| − | + | {{#drawio:datsys-4}} | |
| − | Abbildung: Struktur einer | + | ''Abbildung 4: Aufteilung in Blockgruppen und Struktur einer Gruppe'' |
| − | Superblock, Inode-Tabelle und | + | {| 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. | ||
| + | |||
| + | $ filefrag -v grossedatei.img | ||
| + | |||
| + | ===Maximale Größen=== | ||
| − | {| | + | {| class="wikitable" |
| − | + | ! Dateisystem !! Blockgröße !! max. Dateigröße !! max. Dateisystem | |
| − | |||
| − | |||
| − | |||
| − | Dateisystem | ||
| − | |||
| − | |||
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | ext2 / ext3 || 4 KiB || 2 TiB || 16 TiB |
| − | | | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
|- | |- | ||
| − | | | + | | ext4 || 4 KiB || 16 TiB || 1 EiB (mit Feature <code>64bit</code>) |
| − | | | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | | | ||
| − | | | ||
| − | |||
|} | |} | ||
| − | + | 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.
rmlö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.




