Add native Go ext4 filesystem image creator#280
Merged
dmcgowan merged 1 commit intocontainerd:mainfrom Apr 14, 2026
Merged
Conversation
hsiangkao
reviewed
Apr 12, 2026
4e367e7 to
f1cca45
Compare
Pure Go implementation of ext4 formatting that produces valid, optimized sparse images without requiring mkfs.ext4 or any host binaries. Output is byte-comparable to mkfs.ext4. Signed-off-by: Derek McGowan <derek@mcg.dev>
f1cca45 to
c14c0e8
Compare
austinvazquez
approved these changes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pure Go implementation of ext4 formatting that produces valid, optimized sparse images without requiring mkfs.ext4 or any host binaries. Output is byte-comparable to mkfs.ext4.
This is designed to be used with the erofs snapshotter to remove the dependency on a host binary and speed up upper creation to speed up overall container startup time.
Why not an existing implementation?
The only Go library that supports ext4 creation is go-diskfs. Other Go ext4 packages (dsoprea/go-ext4, masahiro331/go-ext4-filesystem) are read-only. Microsoft's hcsshim/ext4/tar2ext4 converts tarballs to ext4 but does not support creating empty formatted images.
go-diskfs is a general-purpose disk and filesystem library (~9,000 lines for ext4 alone, plus FAT12/16/32, ISO 9660, squashfs, and GPT/MBR partitioning). It seems to be designed for writing to block devices, not creating sparse file images. Several aspects make it impractical for our use case:
Eager zero-fill architecture. go-diskfs explicitly writes zeros to every inode table for every block group (
ext4.go:3069), every bitmap (ext4.go:3045-3057), and the entire journal in 1 MiB chunks (ext4.go:2800-2816). This destroys file sparseness — a 256 MiB image consumes 12 MiB on disk vs 4 MiB with sparse writes. Changing this requires rewriting the creation path acrossinitGroupDescriptorTables,buildGroupDescriptorsFromSuperblock,initJournal, and theCreateorchestration (~300 lines spanning multiple functions). The layout calculations could survive, but the write path would be entirely new.Fails e2fsck at 256 MiB and above. Empty block groups are never marked with
INODE_UNINITorBLOCK_UNINITflags (ext4.go:3367). With default settings, creation crashes at 1 GiB with a journal extent tree error. This indicates the library has not been heavily exercised at sizes relevant to container images.18 transitive dependencies. Four compression libraries (lz4, xz, lzo, zstd), logrus, xattr handling, and others — none used by the ext4 code path.
Benchmarks (256 MiB image)
Formatmkfs.ext4(optimized)mkfs.ext4(defaults)The native formatter performs the same work as
mkfs.ext4— the speed difference vsmkfs.ext4(optimized) is primarily fork/exec and process startup overhead, not the formatting itself. Themkfs.ext4C implementation does the same sparse-aware writes under the same optimized flags. The native formatter avoids this process overhead entirely and requires no host binaries, while producing byte-comparable output (identical superblock fields, block layout, and bitmap content — differing only in UUID and derived checksums). go-diskfs is 20x slower due to its eager zero-fill write path.Features
INODE_UNINIT/BLOCK_UNINITflags on empty groups