mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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
> 

  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®