FS: Ext4

Siehe auch

Verwandte Artikel
Offizielle Dokumentation
  • man ext4, man mke2fs, man tune2fs, man e2fsck, man resize2fs

Linuxfabrik

Ext4 wurde 2006 vorgestellt und ist seit Kernel 2.6.28 (2008) als stabiles Dateisystem im Mainline-Kernel verankert; davor existierte der Code ab 2.6.19 als experimentelles ext4dev. In RHEL war Ext4 in Version 5.3 als Technology Preview enthalten und ab RHEL 6 das Default-Dateisystem. Seit RHEL 7 ist XFS der Default (siehe Filesysteme). Die Maximalgrössen für Datei, Dateisystem und Unterverzeichnisse stehen in der Limits-Tabelle in Filesysteme; Dateinamen dürfen bis zu 255 Zeichen lang sein.

Ext4 beginnt mit einem Superblock, in dem unter anderem die Blockgrösse, die Anzahl der Blöcke und Inodes, die Anzahl der freien Blöcke und Inodes sowie Mount-Informationen liegen. Der Rest der Platte wird in Blockgruppen verwaltet. Mit dem Default-Feature sparse_super liegen Backup-Superblöcke nicht in jeder Blockgruppe, sondern nur in Gruppe 1 sowie in den Gruppen, deren Nummer eine Potenz von 3, 5 oder 7 ist.

Grössen (Standard):

  • Block: 4 KiB

  • Blockgruppe: 128 MiB

  • Inode: 256 Bytes

Dateisystem erstellen

# default ext4 with the current feature set
mkfs.ext4 /dev/vdb

# enable the quota feature at creation time (see Quota below)
mkfs.ext4 -O quota -E quotatype=usrquota:grpquota:prjquota /dev/vdb

Die Defaults stammen aus /etc/mke2fs.conf: neben Blockgrösse 4 KiB und Inode-Grösse 256 B wird ein Inode je 16 KiB angelegt (inode_ratio). Das Default-Feature-Set umfasst unter anderem extent, 64bit, metadata_csum, dir_nlink und huge_file.

Dateisystem vergrössern und verkleinern

resize2fs vergrössert ein Ext4-Dateisystem online, also im gemounteten Zustand. Verkleinern ist nur im ausgehängten Zustand möglich.

# grow to fill the underlying block device (e.g. after an LVM lvextend)
resize2fs /dev/vg_data/lv_data

# grow to a specific size
resize2fs /dev/vg_data/lv_data 500G

# shrink (unmounted only); force a check first
umount /data
e2fsck -f /dev/vdb
resize2fs /dev/vdb 100G

Bei LVM erledigt lvextend --resizefs das Vergrössern von Logical Volume und Dateisystem in einem Schritt.

Dateisystem prüfen und reparieren

Ein Ext4-Dateisystem muss im ausgehängten Zustand geprüft werden. „FSCK“ steht für „FileSystem ChecK“; für Ext4 ist das Werkzeug e2fsck (gleichbedeutend mit fsck.ext4).

# dry run: report problems without changing anything
e2fsck -fn /dev/vdb

# automated repair (preen): apply only safe fixes, no interactive
# prompts. suitable for the boot path.
e2fsck -fp /dev/vdb

# interactive repair when preen bails out
e2fsck -f /dev/vdb

Ist der primäre Superblock beschädigt, lässt sich aus einem Backup-Superblock reparieren. Die Positionen der Backups auslesen und dann gezielt einen davon verwenden:

# list primary and backup superblock locations of the existing FS
dumpe2fs /dev/vdb | grep --ignore-case superblock

# repair using the first backup superblock (block 32768 with 4 KiB blocks)
e2fsck -b 32768 /dev/vdb

Das Wurzeldateisystem lässt sich im laufenden Betrieb nicht aushängen; seine Prüfung erfordert einen Rescue- oder Live-Boot. Wann die letzten Checks gelaufen sind:

tune2fs -l /dev/vdb | grep --extended-regexp --ignore-case "mount count|check interval|last|next"

Quota

Ext4 kennt zwei Quota-Modi: den modernen, journaled Modus mit dem quota-Feature im Dateisystem, und den älteren Modus mit den externen Dateien aquota.user und aquota.group im Root des Dateisystems. Der externe Modus ist deprecated; der Kernel selbst weist beim Mount eines solchen Dateisystems darauf hin:

Your kernel probably supports ext4 quota feature but you are using external
quota files. Please switch your filesystem to use ext4 quota feature as
external quota files on ext4 are deprecated.

Im modernen Modus liegt der Quota-Status in versteckten Inodes (User-Quota in Inode 3, Group-Quota in Inode 4; der Project-Quota-Inode wird dynamisch vergeben) und läuft mit dem Journal mit. Damit entfallen einige Schritte, die im legacy Modus zwingend waren. Diese Tools und Befehle sind im modernen Modus nicht mehr nötig und sollten nicht verwendet werden:

  • quotacheck - das Journal hält den Quota-Status konsistent.

  • quotaon / quotaoff zum Aktivieren bzw. Deaktivieren - Quotas sind nach dem Mount automatisch aktiv (quotaon -p zum Anzeigen des Status ist weiterhin nützlich).

  • Mount-Optionen usrjquota=aquota.user, grpjquota=aquota.group, jqfmt=vfsv1 - diese referenzieren die deprecated externen Dateien.

  • Manuelles Anlegen oder Pflegen der Dateien aquota.user und aquota.group.

Wichtig: Das quota-Feature alleine aktiviert nur das Tracking der Nutzung. Damit Limits auch erzwungen werden, müssen die Mount-Optionen usrquota, grpquota und/oder prjquota gesetzt sein. Mit defaults als einziger Mount-Option werden Quotas zwar gezählt, aber nicht durchgesetzt.

Neues Dateisystem mit Quota:

dnf install --assumeyes quota
mkfs.ext4 -O quota -E quotatype=usrquota:grpquota:prjquota /dev/vdb

echo '/dev/vdb /data ext4 defaults,usrquota,grpquota,prjquota 0 0' >> /etc/fstab
mkdir --parents /data
mount /data

# quotas are tracked and enforced as soon as the FS is mounted;
# no quotacheck, no quotaon needed. The --print-state form below
# only queries the on/off state, it does not activate anything.
quotaon --print-state --user --project --group /data

# mask the per-mount quotaon@.service instance that
# systemd-fstab-generator creates from the quota mount options.
# On a modern setup the kernel already enabled quotas, so the unit
# would fail with "File exists" (systemd #29905). systemd-escape
# handles the mountpoint -> instance name escaping for us.
systemctl mask "$(systemd-escape --template=quotaon@.service --path /data)"

# set a user quota (interactive, opens $EDITOR)
edquota --user user1
# columns:
# 1. blocks: current usage
# 2. soft:   soft limit (blocks)
# 3. hard:   hard limit (blocks)
# 4. inodes: current usage
# 5. soft:   soft limit (inodes)
# 6. hard:   hard limit (inodes)
#
# value 0 = no limit
# block values are in kibibytes; K, M, G, T suffixes are accepted

# the soft limit may be exceeded for the duration of the grace period.
# once grace time is over, the user cannot allocate more until usage
# drops back below the soft limit.

# set a group quota
edquota --group myusergroup

# non-interactive equivalent:
# setquota --user  user1       SOFT_KB HARD_KB SOFT_INODES HARD_INODES /data
# setquota --group myusergroup SOFT_KB HARD_KB SOFT_INODES HARD_INODES /data

# project quota:
# 1. assign a name to a unique project ID
echo 'test_project1:7' >> /etc/projid
mkdir /data/project1
# 2. tag the directory with the project ID and the inheritance flag
chattr +P -p 7 /data/project1
# 3. verify
lsattr -p /data
# 4. set the limits
edquota --project test_project1

# grace period (applies to all filesystems with quotas enabled)
edquota --edit-period --user
edquota --edit-period --group
edquota --edit-period --project

# show current usage and limits
quota --verbose --user user1
quota --verbose --group myusergroup
quota --verbose --project test_project1

# full report (one call per type; --user, --group, --project cannot be combined)
repquota --human-readable --user    /data
repquota --human-readable --group   /data
repquota --human-readable --project /data

Die verschiedenen Quotas (User, Gruppen, Projekt) sind komplett voneinander getrennt:

  • Die User-Quota zählt alle Files, die dem User gehören (anhand der File Permissions).

  • Die Gruppen-Quota zählt alle Files, die der Gruppe gehören (anhand der File Permissions).

  • Die Projekt-Quota zählt alle Files, die in den Projekt-Ordnern sind (anhand der File Attributes).

Was passiert, wenn die User-Quota (1G soft, 1.5G hard) aufgebraucht ist, aber die Gruppen-Quota (2G soft, 2.5G hard) noch nicht?
fallocate --length 1200M test_file1
# vdb: warning, user block quota exceeded.

fallocate --length 1200M test_file2
# vdb: write failed, user block limit reached.
# fallocate: fallocate failed: Disk quota exceeded
# only wrote 300M, filling up the hard limit of 1500M

Das heisst, die niedrigere der beiden Quotas gilt.

Was passiert, wenn die Gruppen-Quota (1G soft, 1.5G hard) aufgebraucht ist, aber die User-Quota (2G soft, 2.5G hard) noch nicht?

Gleiches Verhalten wie beim umgekehrten Szenario. Allerdings kann die Nutzung der Gruppen-Quota reduziert werden, indem die Group der Datei geändert wird:

chgrp myusergroup test_file1
fallocate --length 1200M test_file2

Somit kann auch die zweite 1.2G-Datei angelegt werden, da test_file1 jetzt der Gruppe myusergroup gehört und damit die ursprüngliche Gruppen-Quota nicht mehr belastet.

Was passiert, wenn für user1 und user2 User-Quotas gesetzt sind und via ACL beide Benutzer Zugriff auf die Datei haben?

Die Datei zählt nur zur Quota des Besitzers. Gruppen-ACLs verhalten sich gleich. ACLs haben also keinen Einfluss auf die Quota.

Zu welchen Quotas zählen Dateien in Projekt-Ordnern?

Zu allen zutreffenden Quotas, also zur User-, Gruppen- sowie Projekt-Quota. Wie immer gilt die niedrigste Quota.

Gelten gesetzte Quotas für alle Mountpoints / Filesysteme?

Nein. Quotas werden pro Dateisystem aktiviert (-O quota Feature plus passende Mount-Optionen) und auch pro Dateisystem gesetzt.

Was ist die beste Vorgehensweise beim Setzen von Quotas für die Home-Verzeichnisse?

Für die Anwendung ist es am sinnvollsten, eine User-Quota pro Benutzer für das / oder /home Filesystem zu setzen.

Was ist die beste Vorgehensweise beim Setzen von Quotas für eine shared Daten-Partition?

Hier empfiehlt es sich, nur Projekt-Quotas zu verwenden und den Zugriff über File Permissions zu regeln. Das Konzept ist einfach und für Endnutzer verständlich. Zum Beispiel:

# only root may create new project folders
chmod 0755 /data

# first project: only user1 is allowed
mkdir /data/project1
chown --recursive user1:user1 /data/project1
echo 'project1:1' >> /etc/projid
chattr +P -p 1 /data/project1
edquota --project project1

# second project: myusergroup is allowed
mkdir /data/project2
chown --recursive user1:myusergroup /data/project2

# make sure the group always has rwx permissions and that this
# gets applied to new files
setfacl --recursive --modify         group:myusergroup:rwx /data/project2
setfacl --recursive --default --modify group:myusergroup:rwx /data/project2

# ensure the project ID is unique
# human-readable-name:project-id
echo 'project2:2' >> /etc/projid

# add folder to project with ID 2
chattr +P -p 2 /data/project2

# verify the project IDs assigned per file/folder
lsattr -p /data

# set the quota for the project
edquota --project project2

# check the quotas
repquota --human-readable --project /data
Backup und Restore der Quota-Konfiguration

Hier am Beispiel von /data:

mp='/data'

backup="/root/quota-backup-$mp-$(date +%Y%m%d-%H%M%S)"
mkdir --parents "$backup"

# human-readable snapshot (one file per quota type; --user --group --project cannot be combined)
repquota --verbose --user    "$mp" > "$backup/user.txt"
repquota --verbose --group   "$mp" > "$backup/group.txt"
repquota --verbose --project "$mp" > "$backup/project.txt"

# machine-parseable (csv) for diff and restore
repquota --user    --output=csv "$mp" > "$backup/user.csv"
repquota --group   --output=csv "$mp" > "$backup/group.csv"
repquota --project --output=csv "$mp" > "$backup/project.csv"

# filesystem feature flags, current mount options, fstab, project mappings
tune2fs -l "$(findmnt --noheadings --list --output SOURCE "$mp")" > "$backup/tune2fs-l.txt"
grep " $mp " /proc/mounts                                         > "$backup/proc-mounts.txt"
cp /etc/fstab                                                       "$backup/fstab.txt"
cp /etc/projid /etc/projects                                        "$backup/" 2>/dev/null

Restore einer einzelnen Limit-Zeile aus dem CSV-Backup:

# CSV columns: name, BlockStatus, FileStatus, BlockUsed, BlockSoftLimit,
# BlockHardLimit, BlockGrace, FileUsed, FileSoftLimit, FileHardLimit, FileGrace
# the *Used and *Grace columns are read-only and computed by the kernel;
# setquota only needs the four limit values.

setquota --user    user1   SOFT_KB HARD_KB SOFT_INODES HARD_INODES /data
setquota --group   mygroup SOFT_KB HARD_KB SOFT_INODES HARD_INODES /data
setquota --project myproj  SOFT_KB HARD_KB SOFT_INODES HARD_INODES /data

Vollständiges Re-Apply aller Limits aus dem CSV als awk-Einzeiler (Beispiel User-Quotas):

tail --lines=+2 "$backup/user.csv" \
    | awk --field-separator=, '$5!=0 || $6!=0 || $9!=0 || $10!=0 {
          printf "setquota --user %s %s %s %s %s /data\n", $1, $5, $6, $9, $10
      }'

Die Ausgabe inspizieren, dann nach | sh pipen, um den Restore auszuführen.

Migration eines Legacy-Setups in den modernen Modus

Ausgangslage: mkfs.ext4 ohne -O quota, Mount mit usrquota,grpquota, aquota.user und aquota.group als sichtbare Dateien im FS-Root, Kernel gibt beim Mount die folgende Warnung aus:

Your kernel probably supports ext4 quota feature but you are using external
quota files. Please switch your filesystem to use ext4 quota feature as
external quota files on ext4 are deprecated.

Vor der Migration ein Backup anlegen (siehe oben). Beispiel /data auf /dev/vdb:

# 1. unmount (active legacy quotas do not block umount)
umount /data

# 2. enable the quota feature and pick the quota types
#    (in-place, unmounted FS only). Existing usage and limits
#    are migrated into the hidden inodes.
tune2fs -O quota -Q usrquota,grpquota,prjquota /dev/vdb

# 3. update /etc/fstab: replace the old mount options
#    (usrquota,grpquota plus any usrjquota=, grpjquota=, jqfmt=...)
#    with: defaults,usrquota,grpquota,prjquota

# 4. remount
mount /data

# 5. remove the now-stale visible quota files
rm /data/aquota.user /data/aquota.group

# 6. verify
quotaon --print-state --user --project --group /data
repquota --human-readable --user /data

tune2fs -O quota liest die bestehenden aquota.user/aquota.group-Dateien aus und schreibt deren Inhalt in die neuen hidden inodes: Soft- und Hard-Limits, aktueller Verbrauch (Blocks und Inodes) sowie laufende Grace-Periods bleiben erhalten. Project-Quotas existieren im Legacy-Modus nicht; sie werden mit der Aktivierung des Features neu angelegt und sind danach leer.

Für / ist ein Rescue- oder Live-Boot nötig, da / im laufenden Betrieb nicht ausgehängt werden kann.

Nach der Migration die quotaon@<mount>.service-Instanzen, die systemd-fstab-generator aus den Quota-Mount-Optionen erzeugt, dauerhaft maskieren. Im modernen Modus aktiviert der Kernel die Quotas selbst; ein erneutes quotaon schlägt mit File exists fehl und macht die Unit zu einer dauerhaft fehlschlagenden Unit. systemctl disable reicht hier nicht, weil die Units vom Generator unter /run/ neu instanziert werden - Details und Begründung in Systemd Unit-Files:

# one mask call per affected mount. systemd-escape produces the
# correct unit instance name even for mountpoints with hyphens.
systemctl mask "$(systemd-escape --template=quotaon@.service --path /data)"

Bekannt als upstream-Problem systemd #29905, ohne Fix. Die Quota-Optionen aus der /etc/fstab zu entfernen ist kein Workaround: ohne sie aktiviert der Kernel zwar das Quota-Tracking, erzwingt die Limits aber nicht.

quotaon@<mount>.service schlägt fehl

systemd-fstab-generator instanziert für jeden /etc/fstab-Eintrag mit usrquota/grpquota/prjquota automatisch eine quotaon@<mount>.service-Unit, die nach dem Mount ein quotaon ausführt. Im modernen Modus hat der Kernel die Quotas zu diesem Zeitpunkt bereits aktiviert; der Aufruf schlägt mit File exists fehl. Funktionale Auswirkung gibt es keine (Tracking und Enforcement laufen), aber die Unit erscheint dauerhaft in systemctl --failed. Das Problem ist als systemd #29905 upstream gemeldet und derzeit ohne Fix. Workaround: die jeweilige Instanz per systemctl mask maskieren (systemctl disable reicht nicht, da die Unit von einem Generator verlangt wird, siehe Systemd Unit-Files).

Snapshots

Ext4 kennt keine eigenen Snapshots. Auf der LVM-Schicht darunter lässt sich ein konsistenter Snapshot über fsfreeze plus lvcreate --snapshot anlegen; das Vorgehen samt Wegsichern und Restore steht in Filesysteme.

Troubleshooting

mount: wrong fs type, bad option, bad superblock

Der primäre Superblock ist beschädigt. Aus einem Backup-Superblock prüfen und reparieren (siehe oben), dann erneut mounten.

resize2fs: On-line shrinking not supported

Verkleinern geht nur im ausgehängten Zustand. Dateisystem aushängen, e2fsck -f laufen lassen, dann resize2fs mit Zielgrösse.

The ext4 file system creation ... features ... not supported

Das e2fsprogs-Werkzeug auf dem System ist älter als das Feature-Set des Dateisystems. Aktuelleres e2fsprogs verwenden oder das Dateisystem ohne das fehlende Feature anlegen.