Skip to content

btrfs-progs: add detection for unexpected file extents - #1155

Open
adam900710 wants to merge 5 commits into
kdave:develfrom
adam900710:fsck_odd_file_extent
Open

btrfs-progs: add detection for unexpected file extents#1155
adam900710 wants to merge 5 commits into
kdave:develfrom
adam900710:fsck_odd_file_extent

Conversation

@adam900710

Copy link
Copy Markdown
Collaborator

There is a kernel patch (*) which mentioned a corrupted fs image where
there is at least one file extent item which shouldn't exist, as the
inode is not a symlink or regular file.

It turns out btrfs check can not detect such case.

The first 4 patches introduce the ability to generate such image.

The 4th patch adds the detection ability, and the last one is the test
case.

*: https://lore.kernel.org/linux-btrfs/20260817132051.267646-1-gality369@gmail.com/

@adam900710
adam900710 force-pushed the fsck_odd_file_extent branch 3 times, most recently from f8d733d to 63fbdc2 Compare August 18, 2026 07:37
This allows us to do more accurate inode item corruption, not only to
inject random number, but more targeted values.

This feature will be later utilized to change inode's mode from REG to
BLK.

Assisted-by: LLM (coding)
Signed-off-by: Qu Wenruo <wqu@suse.com>
…option

For now this only affects DIR_ITEM location objectid corruption, but
later this will be utilized for more dir item member corruption.

Signed-off-by: Qu Wenruo <wqu@suse.com>
With this feature and the previous inode corruption, we can change the
type in inode item, dir item, dir index to be consistent with each
other.

Assisted-by: LLM (coding)
Signed-off-by: Qu Wenruo <wqu@suse.com>
File extent items should only exist for regular and symlink inodes.
And for symlink inodes, the file extent must be inlined.

Add such check for lowmem mode to detect those invalid file extents.

Now for a corrupted image with the following fs tree layout:

	item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
		generation 3 transid 9 size 12 nbytes 16384
		block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0
		sequence 1 flags 0x0(none)
	item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
		index 0 namelen 2 name: ..
	item 2 key (256 DIR_ITEM 496027801) itemoff 16075 itemsize 36
		location key (257 INODE_ITEM 0) type BLKDEV
		transid 9 data_len 0 name_len 6
		name: foobar
	item 3 key (256 DIR_INDEX 2) itemoff 16039 itemsize 36
		location key (257 INODE_ITEM 0) type BLKDEV
		transid 9 data_len 0 name_len 6
		name: foobar
	item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160
		generation 9 transid 9 size 8192 nbytes 8192
		block group 0 mode 60660 links 1 uid 0 gid 0 rdev 0
		sequence 2 flags 0x0(none)
	item 5 key (257 INODE_REF 256) itemoff 15863 itemsize 16
		index 2 namelen 6 name: foobar
	item 6 key (257 EXTENT_DATA 0) itemoff 15810 itemsize 53
		generation 9 type 1 (regular)
		extent data disk byte 13631488 nr 8192
		extent data offset 0 nr 8192 ram 8192
		extent compression 0 (none)

Lowmem mode will detect the error like the following:

 [5/8] checking fs roots
 ERROR: root 5 ino 257 should not have file extent
 ERROR: root 5 INODE[257] nbytes 8192 not equal to extent_size 0
 ERROR: errors found in fs roots
 found 172032 bytes used, error(s) found

For the original mode, it's less strict than the lowmem mode, and it
only rejects the obvious cases, without the extra verification on
inlined extent for symlinks:

 [5/8] checking fs roots
 root 5 inode 257 errors 40, bad file extent
 ERROR: errors found in fs roots
 found 172032 bytes used, error(s) found

Signed-off-by: Qu Wenruo <wqu@suse.com>
The image is created using btrfs-corrupt-block, the fs tree leaf looks
like this:

	item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
		generation 3 transid 9 size 12 nbytes 16384
		block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0
		sequence 1 flags 0x0(none)
	item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
		index 0 namelen 2 name: ..
	item 2 key (256 DIR_ITEM 496027801) itemoff 16075 itemsize 36
		location key (257 INODE_ITEM 0) type BLKDEV <<<
		transid 9 data_len 0 name_len 6
		name: foobar
	item 3 key (256 DIR_INDEX 2) itemoff 16039 itemsize 36
		location key (257 INODE_ITEM 0) type BLKDEV <<<
		transid 9 data_len 0 name_len 6
		name: foobar
	item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160
		generation 9 transid 9 size 8192 nbytes 8192
		block group 0 mode 60660 links 1 uid 0 gid 0 rdev 0 <<<
		sequence 2 flags 0x0(none)
	item 5 key (257 INODE_REF 256) itemoff 15863 itemsize 16
		index 2 namelen 6 name: foobar
	item 6 key (257 EXTENT_DATA 0) itemoff 15810 itemsize 53
		generation 9 type 1 (regular)
		extent data disk byte 13631488 nr 8192
		extent data offset 0 nr 8192 ram 8192
		extent compression 0 (none)

The image is generated by the following steps:

 # mkfs.btrfs -f $dev
 # mount $dev $mnt
 # xfs_io -f -c "pwrite 0 4k" $mnt/foobar
 # umount $mnt

 ## Change the inode's mode from REG to BLK
 # btrfs-corrupt-block -i 257 -f mode --value 25008 $dev

 ## Change the dir item's flag from REG to BLK
 # btrfs-corrupt-block -D 256,84,496027801 -f flags --value 4 $dev

 ## Change the dir index's flag from REG to BLK
 # btrfs-corrupt-block -D 256,96,2 -f flags --value 4 $dev

The inode's mode and dir flags all match, but there is one unexpected
file extent item there.

Both lowmem and original mode should detect such problem.

Signed-off-by: Qu Wenruo <wqu@suse.com>
@adam900710
adam900710 force-pushed the fsck_odd_file_extent branch from 63fbdc2 to 78b7903 Compare August 18, 2026 09:14
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.

1 participant