Skip to content

ext4: scale default block size by filesystem size#407

Draft
eriknordmark wants to merge 1 commit into
diskfs:masterfrom
eriknordmark:ext4-recalculate-blocksize
Draft

ext4: scale default block size by filesystem size#407
eriknordmark wants to merge 1 commit into
diskfs:masterfrom
eriknordmark:ext4-recalculate-blocksize

Conversation

@eriknordmark
Copy link
Copy Markdown

Summary

recalculateBlocksize was a placeholder: every bracket of its size-based
switch set the same sectorsPerBlock = 2, so a default-parameter
Create always used 1 KiB blocks regardless of filesystem size. On
filesystems of a few GiB the journal allocator — capped at 128 MiB =
131072 1-KiB blocks — asks for more blocks than the per-extent cap
(maxBlocksPerExtent = 32768) or the inode's 4-extent root limit can
fit, and Create fails with

could not initialize journal: cannot allocate more than 65535 blocks in
a single extent

(see #402 for the trace).

This change makes recalculateBlocksize actually pick a block size by
filesystem size, matching mke2fs's small-vs-default split: 1 KiB
blocks below 512 MiB, 4 KiB blocks at or above. With 4 KiB blocks a
128 MiB journal needs exactly maxBlocksPerExtent (32768) blocks and
fits in a single extent.

Because resize_inode / reserved-GDT growth in go-diskfs currently
only supports 1 KiB blocks (there's an existing TODO: Properly support resize_inode at the GDT-sizing block, and
TestCreateWithBlockSizes already passes
WithFeatureReservedGDTBlocksForExpansion(false) for non-1 KiB cases),
this also drops the feature when we picked the larger default. A
caller who explicitly sets SectorsPerBlock is unaffected: they pass
their own block size and the default-only path doesn't run.

Test

Added TestCreateMultiGB — Create on 1 GiB and 2 GiB images, validated
with e2fsck -f -n. Both pass with the fix; the 2 GiB case is the
size that reproduces #402 on master. Full go test ./... is green.

Behavior change to flag

This is a visible default change: existing callers who got 1 KiB
blocks back from Create on a >512 MiB filesystem will now get 4 KiB
blocks. Almost certainly the right default (matches mke2fs), but
worth calling out. Callers who need the old behavior can set
Params.SectorsPerBlock = 2 explicitly.

Not in this PR

Large-file writes that need >32768 blocks still hit the same inode
4-extent root limit fixed by no other change — createRootExtentTree
explicitly returns "cannot create root internal node" past 4 entries.
That's a separate, pre-existing limitation; this PR closes #402 for
the journal-allocation case without addressing it. Worth filing as its
own issue.

Fixes #402.

recalculateBlocksize hard-coded 1 KiB blocks for every size bracket,
so a default-parameter Create on a filesystem of a few GiB or more
asked the journal allocator (capped at 128 MiB) for >65535 1-KiB
blocks. That exceeds both the per-extent cap and the inode's 4-extent
root limit, and Create returned "could not initialize journal: cannot
allocate more than 65535 blocks in a single extent". Follow mke2fs's
small-vs-default split instead: 1 KiB blocks below 512 MiB, 4 KiB
blocks at or above. A 128 MiB journal then fits in a single
maxBlocksPerExtent extent regardless of filesystem size. When *we*
picked the non-1 KiB default, also disable
reservedGDTBlocksForExpansion because resize_inode support is gated on
1 KiB blocks (existing TODO at the gdt sizing block).

Fixes diskfs#402.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ext4: CreateFilesystem fails on multi-GB partitions ("cannot allocate more than 65535 blocks in a single extent")

1 participant