From: Boris Burkov <boris@bur.io>
To: Siddharth Mishra <smish149@asu.edu>
Cc: dsterba@suse.com, wqu@suse.com, josef@toxicpanda.com,
fdmanana@suse.com, mason@kernel.org, linux-btrfs@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 3/5] btrfs: tree-checker: reject keyed refs not matching the extent type
Date: Wed, 4 Nov 2026 11:29:02 -0800 [thread overview]
Message-ID: <20261104192902.GE3301639@zen.localdomain> (raw)
In-Reply-To: <20261104102323.4090290-4-smish149@asu.edu>
On Wed, Nov 04, 2026 at 03:23:21AM -0700, Siddharth Mishra wrote:
> [BACKGROUND]
> When the refs of an extent do not fit into its extent item, the others
> are stored as keyed ref items with the same objectid, right after the
> extent item:
>
> TREE_BLOCK: TREE_BLOCK_REF and SHARED_BLOCK_REF items
> DATA: EXTENT_DATA_REF and SHARED_DATA_REF items
>
> [CAUSE]
> check_simple_keyed_refs() and check_extent_data_ref() only verify the
> keyed ref itself. Nothing checks that its type matches the extent it
> belongs to, so a tree block ref for a data extent, or a data ref for a
> tree block, passes the tree-checker. For example this data extent is
> followed by a keyed tree block ref:
>
> item 0 key (13631488 EXTENT_ITEM 32768) itemoff 3797 itemsize 198
> refs 41 gen 9 flags DATA
> (178 0xdea30debbf5f519) extent data backref root 256
> objectid 258 offset 0 count 1
> ...
> item 1 key (13631488 TREE_BLOCK_REF 5) itemoff 3797 itemsize 0
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> tree block backref
>
> The leaf is accepted. When the extent is freed later, the refs do not
> add up and the transaction aborts:
>
> WARNING: fs/btrfs/extent-tree.c:3418 at __btrfs_free_extent
> BTRFS error (device vda state A): Transaction 35 aborted (-EUCLEAN)
> BTRFS info (device vda state EA): forced readonly
>
> [ENHANCEMENT]
> Check each keyed ref against the item right before it. Keyed refs sort
> right after their extent item, so that item is either the extent item
> or another keyed ref of the same extent, and both must be of the same
> kind. Reject a mismatch with -EUCLEAN, so the leaf is refused when it
> is read:
>
> BTRFS critical (device vda): corrupt leaf: block=31678464 slot=1
> extent bytenr=13631488 len=4096 keyed ref type 176 does not match the
> extent type
>
> This is the keyed counterpart of the inline ref check.
>
> If the item before a keyed ref belongs to another extent, its extent
> item is in another leaf and the keyed ref cannot be checked by the
> tree-checker.
>
This one seems the most "juice not worth the squeeze" out of these
patches, but I think the analogy to inline refs is good enough for me to
justify it.
Reviewed-by: Boris Burkov <boris@bur.io>
> Signed-off-by: Siddharth Mishra <smish149@asu.edu>
> ---
> fs/btrfs/tree-checker.c | 48 +++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 46 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
> index db446c8af..d966243c9 100644
> --- a/fs/btrfs/tree-checker.c
> +++ b/fs/btrfs/tree-checker.c
> @@ -1854,6 +1854,50 @@ static int check_extent_item(struct extent_buffer *leaf,
> return 0;
> }
>
> +static int check_keyed_ref_extent_type(const struct extent_buffer *leaf,
> + const struct btrfs_key *key, int slot)
> +{
> + const bool is_tree_block_ref = (key->type == BTRFS_TREE_BLOCK_REF_KEY ||
> + key->type == BTRFS_SHARED_BLOCK_REF_KEY);
> + struct btrfs_key prev_key;
> + bool prev_is_tree_block;
> +
> + if (slot == 0)
> + return 0;
> + btrfs_item_key_to_cpu(leaf, &prev_key, slot - 1);
> + if (prev_key.objectid != key->objectid)
> + return 0;
> +
> + switch (prev_key.type) {
> + case BTRFS_EXTENT_ITEM_KEY:
> + case BTRFS_METADATA_ITEM_KEY: {
> + struct btrfs_extent_item *ei;
> +
> + ei = btrfs_item_ptr(leaf, slot - 1, struct btrfs_extent_item);
> + prev_is_tree_block = (btrfs_extent_flags(leaf, ei) &
> + BTRFS_EXTENT_FLAG_TREE_BLOCK);
> + break;
> + }
> + case BTRFS_TREE_BLOCK_REF_KEY:
> + case BTRFS_SHARED_BLOCK_REF_KEY:
> + prev_is_tree_block = true;
> + break;
> + case BTRFS_EXTENT_DATA_REF_KEY:
> + case BTRFS_SHARED_DATA_REF_KEY:
> + prev_is_tree_block = false;
> + break;
> + default:
> + return 0;
> + }
> + if (unlikely(prev_is_tree_block != is_tree_block_ref)) {
> + extent_err(leaf, slot,
> + "keyed ref type %u does not match the extent type",
> + key->type);
> + return -EUCLEAN;
> + }
> + return 0;
> +}
> +
> static int check_simple_keyed_refs(struct extent_buffer *leaf,
> struct btrfs_key *key, int slot)
> {
> @@ -1892,7 +1936,7 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf,
> key->offset, leaf->fs_info->sectorsize);
> return -EUCLEAN;
> }
> - return 0;
> + return check_keyed_ref_extent_type(leaf, key, slot);
> }
>
> static int check_extent_data_ref(struct extent_buffer *leaf,
> @@ -1953,7 +1997,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
> return -EUCLEAN;
> }
> }
> - return 0;
> + return check_keyed_ref_extent_type(leaf, key, slot);
> }
>
> #define inode_ref_err(eb, slot, fmt, args...) \
> --
> 2.54.0
>
next prev parent reply other threads:[~2026-11-04 19:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 10:23 [PATCH 0/5] btrfs: owner refs and tree blocks Siddharth Mishra
2026-11-04 10:23 ` [PATCH 1/5] btrfs: skip tree blocks in btrfs_get_extent_owner_root() Siddharth Mishra
2026-11-04 19:13 ` Boris Burkov
2026-11-04 10:23 ` [PATCH 2/5] btrfs: tree-checker: reject inline refs not matching the extent type Siddharth Mishra
2026-11-04 19:24 ` Boris Burkov
2026-11-04 19:56 ` Siddharth Mishra
2026-11-04 10:23 ` [PATCH 3/5] btrfs: tree-checker: reject keyed " Siddharth Mishra
2026-11-04 19:29 ` Boris Burkov [this message]
2026-11-04 10:23 ` [PATCH 4/5] btrfs-progs: check: count non-skinny tree blocks in simple quotas Siddharth Mishra
2026-11-04 19:21 ` Boris Burkov
2026-11-04 21:30 ` [PATCH v2] " Siddharth Mishra
2026-11-04 10:23 ` [PATCH 5/5] btrfs-progs: tune: do not remove owner refs from tree blocks Siddharth Mishra
2026-11-04 19:18 ` Boris Burkov
2026-11-04 22:50 ` [PATCH 0/5] btrfs: owner refs and " Qu Wenruo
2026-11-04 23:16 ` Siddharth Mishra
2026-11-04 23:17 ` Qu Wenruo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261104192902.GE3301639@zen.localdomain \
--to=boris@bur.io \
--cc=dsterba@suse.com \
--cc=fdmanana@suse.com \
--cc=josef@toxicpanda.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mason@kernel.org \
--cc=smish149@asu.edu \
--cc=wqu@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®