git: ext2fs: read ext4 extent-mapped inodes
Aaron LI
aly at crater.dragonflybsd.org
Fri Oct 23 06:19:04 PDT 2026
commit 3f67cba06f33019f378c4b8cd64bab8bc254b77f
Author: David Bidner <david at crap.solutions>
Date: Thu Oct 22 12:33:34 2026 +0200
ext2fs: read ext4 extent-mapped inodes
DragonFly's ext2fs advertises EXT2F_INCOMPAT_EXTENTS, but the extent
lookup path is stubbed out: ext4_bmapext() and ext4_ext_find_extent()
both return EINVAL. mkfs.ext4 creates every inode extent-mapped by
default, so a read-only mount of a Linux ext4 filesystem succeeds
(statfs reads only the superblock) but every directory lookup and
readdir fails with EINVAL.
Port the read-only extent tree walk and the extent bmap from FreeBSD
main (d7d237ce731f), following FreeBSD's extent read path
(d7511a40a749, b394cd1e28f1, 5679656e09fb). The extent write path
(allocation, truncation and removal) remains unimplemented.
The path array is sized EXT4_EXT_DEPTH_MAX + 1: FreeBSD accepts
eh_depth == EXT4_EXT_DEPTH_MAX but allocates only EXT4_EXT_DEPTH_MAX
entries and indexes the last one, one past the end.
Validation and unwritten-extent handling belong to the same reader:
- Release the buffer when bread() fails while walking an extent tree
(DragonFly bread() returns the buffer even on error; the caller must
brelse() it), which otherwise leaves the cache locked and a later
access or unmount hangs.
- Reject an index node with eh_entries == 0 and eh_depth > 0: it passed
validation and ext4_ext_binsearch_index() then ran on an empty node
(KASSERT on kernels with INVARIANTS, including X86_64_GENERIC).
- Require leaf extents to be ordered and non-overlapping by comparing
against one past the previous extent's last block; the previous check
skipped the comparison when that value was zero, so a corrupt tree
with overlapping extents starting at block 0 passed.
- Require the index entries of one node to have strictly increasing
ei_block (the first entry may start anywhere); equal or swapped
entries passed and lookups picked an arbitrary child.
- Treat unwritten extents as holes in ext4_bmapext(): strip the
unwritten bit (bit 15 of ee_len, EXT_INIT_MAX_LEN), use the real
length for the runs and leave the block unmapped so reads return
zeros instead of stale disk data.
Bug: https://bugs.dragonflybsd.org/issues/3451
Bug: https://bugs.dragonflybsd.org/issues/3355
Summary of changes:
sys/vfs/ext2fs/ext2_bmap.c | 73 +++++++-
sys/vfs/ext2fs/ext2_extents.c | 416 +++++++++++++++++++++++++++++++++++++++---
sys/vfs/ext2fs/ext2_extern.h | 2 +-
3 files changed, 466 insertions(+), 25 deletions(-)
http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/3f67cba06f33019f378c4b8cd64bab8bc254b77f
--
DragonFly BSD source repository
More information about the Commits
mailing list