Re: [PATCH 5/5] btrfs-progs: tune: do not remove owner refs from tree blocks
From: Boris Burkov
Date: Wed Nov 04 2026 - 14:37:06 EST
On Wed, Nov 04, 2026 at 03:23:23AM -0700, Siddharth Mishra wrote:
> [BUG]
> On a filesystem without skinny-metadata, "btrfstune --remove-simple-quota"
> can corrupt the extent items of tree blocks:
>
> before:
> item 31 key (30756864 EXTENT_ITEM 4096) itemoff 2363 itemsize 51
> refs 1 gen 6 flags TREE_BLOCK
> tree block key (940 INODE_ITEM 0) level 0
> (176 0x5) tree block backref root FS_TREE
> after:
> item 31 key (30756864 EXTENT_ITEM 4096) itemoff 2372 itemsize 42
> refs 1 gen 6 flags TREE_BLOCK
> tree block key (0 UNKNOWN.0 1456) level 0
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> and "btrfs check" then reports "backpointer mismatch" for each of them.
>
> [CAUSE]
> remove_owner_refs() takes the first inline ref right after the
> btrfs_extent_item of every EXTENT_ITEM. For a tree block without
> skinny-metadata that is the btrfs_tree_block_info. If the lowest byte of
> its first key objectid is BTRFS_EXTENT_OWNER_REF_KEY (172, here inode
> 940 = 0x3ac), the tree block info is taken as an owner ref and 9 bytes of
> it are removed.
>
> The check for an extent item without inline refs is also off by one: it
> reads the type byte when ptr == item_end.
>
> [FIX]
> Owner refs are only added to data extents, so skip extent items with the
> TREE_BLOCK flag, and skip the item when ptr >= item_end.
>
Reviewed-by: Boris Burkov <boris@xxxxxx>
> Fixes: 2336a7b921ff ("btrfs-progs: btrfstune: add ability to remove squotas")
> Signed-off-by: Siddharth Mishra <smish149@xxxxxxx>
> ---
> tune/quota.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/tune/quota.c b/tune/quota.c
> index a5f7fb40..187ba4f6 100644
> --- a/tune/quota.c
> +++ b/tune/quota.c
> @@ -132,10 +132,12 @@ search_slot:
> if (found_key.type != BTRFS_EXTENT_ITEM_KEY)
> goto next;
> ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
> + if (btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
> + goto next;
> ptr = (unsigned long)(ei + 1);
> item_end = (unsigned long)ei + btrfs_item_size(leaf, slot);
> /* No inline extent references; accessing type is invalid. */
> - if (ptr > item_end)
> + if (ptr >= item_end)
> goto next;
> iref = (struct btrfs_extent_inline_ref *)ptr;
> type = btrfs_extent_inline_ref_type(leaf, iref);
> --
> 2.54.0
>