mke2fs und sparse files

Um ein SD-Kartenimage zu erstellen wird eine Sparse-Datei angelegt mit einer Größe von knapp 16 GB und darin verschiedene Dateisysteme angelegt:

dd if=/dev/zero of=$$IMAGE_FILE bs=1 count=0 seek=15900MB
 losetup /dev/loop0 $IMAGE_FILE
 {
    ...
    echo 6277120,,0x83
 } | sfdisk -u S -f --no-reread -L ${/dev/loop0}
 partprobe /dev/loop4
 mke2fs /dev/loop0p4

Im Gegensatz zu einer Nicht-Sparse-Datei bzw. einem physikalischen Datenträger bleibt der mke2fs-Vorgang nahezu vollständig stehen.

Dabei nutzt der System-Prozeß [loop0] das System I/O-mäßig fast vollständig aus und verbringt die meiste Zeit im “uninterruptable sleep” (D in ps), obwohl sich die Platte kaum bewegt. Ein Strace auf mke2fs bringt recht zögerliche Zugriffe folgender Art zutage:

_llseek(3, <start>, <ende>, SEEK_SET) = 0
write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0"..., 32768) = 32768

Es stellt sich heraus, daß dies zeitlich mit dem Erzeugen der inode tables in mke2fs zusammenfällt. Offenbar ist die sparse-File-Implementierung zumindest des Kernels unter Ubuntu 12.04 für diesen Anwendungsfall recht ungünstig.

Die Lösung ist mke2fs über die Umgebungsvariable MKE2FS_SYNC zu einem selteneren sync zu zwingen:

export MKE2FS_SYNC=10

Dabei hat sich der schon woanders dokumentierte Wert von 10 bewährt. Interessanterweise führt ein größerer Wert zu dem gleichen Effekt (hängendes mke2fs) wie der Standardwert MKE2FS_SYNC=1.