From: Zygo Blaxell Date: Thu, 10 Sep 2026 14:53:38 +0000 (-0400) Subject: btrfs: stripe_alloc: do not read an inline backref off a keyed-ref extent item X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0842c7db9daae07e7b6aae19898c6d776c49e707;p=linux btrfs: stripe_alloc: do not read an inline backref off a keyed-ref extent item stripe_extents_owned_by() decides whether every extent in a stripe range belongs to one inode by reading the single inline backref of each data extent item. A data extent's only backref is keyed rather than inline when the leaf had no room to grow the item: insert_inline_extent_backref() returns -EAGAIN and insert_extent_backref() adds a separate EXTENT_DATA_REF item. Such an extent item ends right after the header, so the walk read the next item's bytes as an inline ref and btrfs_get_extent_inline_ref_type() warned: BTRFS error (device dm-22): eb 81657856 iref 0x3a5c invalid extent inline ref type 1 WARNING: CPU: 6 PID: 199813 at fs/btrfs/extent-tree.c:380 btrfs_get_extent_inline_ref_type+0xe0/0x190 stripe_extents_owned_by+0x270/0x310 btrfs_alloc_from_inode_stripe_run+0x48e/0x6a0 find_free_extent+0xf9b/0x1870 btrfs_reserve_extent+0x214/0x890 __btrfs_prealloc_file_range+0xf1/0x470 btrfs_fallocate+0xa99/0x10f0 The answer was already the conservative "not owned" (the garbage type is not EXTENT_DATA_REF_KEY), so only the warning and the taint were wrong. Check the item size before reading the inline ref and treat a keyed-ref extent as not owned. Assisted-by: Claude:claude-fable-5 --- diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index f2a33b7bede25..c6af1a34c622d 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1437,6 +1437,21 @@ static bool stripe_extents_owned_by(struct btrfs_fs_info *fs_info, ret = false; goto out; } + /* + * The extent's single backref is keyed, not inline, when the + * leaf had no room to grow the item (insert_inline_extent_backref() + * returns -EAGAIN and insert_extent_backref() adds a separate + * EXTENT_DATA_REF item). Such an extent item ends right after + * the header, and reading an inline ref there reads the next + * item's bytes: btrfs_get_extent_inline_ref_type() warns about + * "invalid extent inline ref type 1". Treat it as not owned; + * the answer is the conservative one either way. + */ + if (btrfs_item_size(leaf, slot) < sizeof(*ei) + + btrfs_extent_inline_ref_size(BTRFS_EXTENT_DATA_REF_KEY)) { + ret = false; + goto out; + } iref = (struct btrfs_extent_inline_ref *)(ei + 1); type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_DATA);