From: Siddharth Mishra <smish149@asu.edu>
To: dsterba@suse.com
Cc: wqu@suse.com, boris@bur.io, josef@toxicpanda.com,
fdmanana@suse.com, mason@kernel.org, linux-btrfs@vger.kernel.org,
linux-kernel@vger.kernel.org, Siddharth Mishra <smish149@asu.edu>
Subject: [PATCH 3/5] btrfs: tree-checker: reject keyed refs not matching the extent type
Date: Wed, 4 Nov 2026 03:23:21 -0700 [thread overview]
Message-ID: <20261104102323.4090290-4-smish149@asu.edu> (raw)
In-Reply-To: <20261104102323.4090290-1-smish149@asu.edu>
[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.
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 10:23 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 ` Siddharth Mishra [this message]
2026-11-04 19:29 ` [PATCH 3/5] btrfs: tree-checker: reject keyed " Boris Burkov
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=20261104102323.4090290-4-smish149@asu.edu \
--to=smish149@asu.edu \
--cc=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=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®