From: David Sterba <dsterba@suse.cz>
To: Qu Wenruo <wqu@suse.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 1/2] btrfs: concentrate all tree block parentness check parameters into one structure
Date: Fri, 11 Nov 2022 17:09:57 +0100 [thread overview]
Message-ID: <20221111160957.GU5824@twin.jikos.cz> (raw)
In-Reply-To: <5776cd5a337d786e57d9e6dbea3e371cc74c14e3.1663133223.git.wqu@suse.com>
On Wed, Sep 14, 2022 at 01:32:50PM +0800, Qu Wenruo wrote:
> There are several different tree block parentness check parameters used
> across several helpers:
>
> - level
> Mandatory
>
> - transid
> Under most cases it's mandatory, but there are several backref cases
> which skips this check.
>
> - owner_root
> - first_key
> Utilized by most top-down tree search routine. Otherwise can be
> skipped.
>
> Those four members are not always mandatory checks, and some of them are
> the same u64, which means if some arguments got swapped compiler will
> not catch it.
>
> Furthermore if we're going to further expand the parentness check, we
> need to modify quite some helpers just to add one more parameter.
>
> This patch will concentrate all these members into a structure called
> btrfs_tree_parent_check, and pass that structure for the following
> helpers:
>
> - btrfs_read_extent_buffer()
> - read_tree_block()
>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/backref.c | 15 ++++++++---
> fs/btrfs/ctree.c | 28 +++++++++++--------
> fs/btrfs/disk-io.c | 59 ++++++++++++++++++++++++-----------------
> fs/btrfs/disk-io.h | 36 ++++++++++++++++++++++---
> fs/btrfs/extent-tree.c | 12 ++++++---
> fs/btrfs/print-tree.c | 13 +++++----
> fs/btrfs/qgroup.c | 18 ++++++++++---
> fs/btrfs/relocation.c | 11 +++++---
> fs/btrfs/tree-log.c | 25 ++++++++++++-----
> fs/btrfs/tree-mod-log.c | 9 +++++--
> 10 files changed, 158 insertions(+), 68 deletions(-)
>
> diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
> index 9d06f8c18b15..abaed23edc7c 100644
> --- a/fs/btrfs/backref.c
> +++ b/fs/btrfs/backref.c
> @@ -777,6 +777,8 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
> struct rb_node *node;
>
> while ((node = rb_first_cached(&tree->root))) {
> + struct btrfs_tree_parent_check check = {0};
The { 0 } should be used.
> +
> ref = rb_entry(node, struct prelim_ref, rbnode);
> rb_erase_cached(node, &tree->root);
>
> @@ -784,8 +786,10 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
> BUG_ON(ref->key_for_search.type);
> BUG_ON(!ref->wanted_disk_byte);
>
> - eb = read_tree_block(fs_info, ref->wanted_disk_byte,
> - ref->root_id, 0, ref->level - 1, NULL);
> + check.level = ref->level - 1;
> + check.owner_root = ref->root_id;
> +
> + eb = read_tree_block(fs_info, ref->wanted_disk_byte, &check);
> if (IS_ERR(eb)) {
> free_pref(ref);
> return PTR_ERR(eb);
> @@ -1330,10 +1334,13 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
> if (ref->count && ref->parent) {
> if (extent_item_pos && !ref->inode_list &&
> ref->level == 0) {
> + struct btrfs_tree_parent_check check = {0};
> struct extent_buffer *eb;
>
> - eb = read_tree_block(fs_info, ref->parent, 0,
> - 0, ref->level, NULL);
> + check.level = ref->level;
> +
> + eb = read_tree_block(fs_info, ref->parent,
> + &check);
> if (IS_ERR(eb)) {
> ret = PTR_ERR(eb);
> goto out;
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index ebfa35fe1c38..44dd9ed3fe63 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -834,19 +834,22 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
> int slot)
> {
> int level = btrfs_header_level(parent);
> + struct btrfs_tree_parent_check check = {0};
> struct extent_buffer *eb;
> - struct btrfs_key first_key;
>
> if (slot < 0 || slot >= btrfs_header_nritems(parent))
> return ERR_PTR(-ENOENT);
>
> BUG_ON(level == 0);
>
> - btrfs_node_key_to_cpu(parent, &first_key, slot);
> + check.level = level - 1;
> + check.transid = btrfs_node_ptr_generation(parent, slot);
> + check.owner_root = btrfs_header_owner(parent);
> + check.has_first_key = true;
> + btrfs_node_key_to_cpu(parent, &check.first_key, slot);
> +
> eb = read_tree_block(parent->fs_info, btrfs_node_blockptr(parent, slot),
> - btrfs_header_owner(parent),
> - btrfs_node_ptr_generation(parent, slot),
> - level - 1, &first_key);
> + &check);
> if (IS_ERR(eb))
> return eb;
> if (!extent_buffer_uptodate(eb)) {
> @@ -1405,10 +1408,10 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
> const struct btrfs_key *key)
> {
> struct btrfs_fs_info *fs_info = root->fs_info;
> + struct btrfs_tree_parent_check check = {0};
> u64 blocknr;
> u64 gen;
> struct extent_buffer *tmp;
> - struct btrfs_key first_key;
> int ret;
> int parent_level;
> bool unlock_up;
> @@ -1417,7 +1420,11 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
> blocknr = btrfs_node_blockptr(*eb_ret, slot);
> gen = btrfs_node_ptr_generation(*eb_ret, slot);
> parent_level = btrfs_header_level(*eb_ret);
> - btrfs_node_key_to_cpu(*eb_ret, &first_key, slot);
> + btrfs_node_key_to_cpu(*eb_ret, &check.first_key, slot);
> + check.has_first_key = true;
> + check.level = parent_level - 1;
> + check.transid = gen;
> + check.owner_root = root->root_key.objectid;
>
> /*
> * If we need to read an extent buffer from disk and we are holding locks
> @@ -1439,7 +1446,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
> * parents (shared tree blocks).
> */
> if (btrfs_verify_level_key(tmp,
> - parent_level - 1, &first_key, gen)) {
> + parent_level - 1, &check.first_key, gen)) {
> free_extent_buffer(tmp);
> return -EUCLEAN;
> }
> @@ -1451,7 +1458,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
> btrfs_unlock_up_safe(p, level + 1);
>
> /* now we're allowed to do a blocking uptodate check */
> - ret = btrfs_read_extent_buffer(tmp, gen, parent_level - 1, &first_key);
> + ret = btrfs_read_extent_buffer(tmp, &check);
> if (ret) {
> free_extent_buffer(tmp);
> btrfs_release_path(p);
> @@ -1479,8 +1486,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
> if (p->reada != READA_NONE)
> reada_for_search(fs_info, p, level, slot, key->objectid);
>
> - tmp = read_tree_block(fs_info, blocknr, root->root_key.objectid,
> - gen, parent_level - 1, &first_key);
> + tmp = read_tree_block(fs_info, blocknr, &check);
> if (IS_ERR(tmp)) {
> btrfs_release_path(p);
> return PTR_ERR(tmp);
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 54b5784a59e5..80aa0ba4ac55 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -253,13 +253,11 @@ int btrfs_verify_level_key(struct extent_buffer *eb, int level,
> * helper to read a given tree block, doing retries as required when
> * the checksums don't match and we have alternate mirrors to try.
> *
> - * @parent_transid: expected transid, skip check if 0
> - * @level: expected level, mandatory check
> - * @first_key: expected key of first slot, skip check if NULL
> + * @check: expected tree parentness check, see the comments of the
> + * structure for details.
> */
> int btrfs_read_extent_buffer(struct extent_buffer *eb,
> - u64 parent_transid, int level,
> - struct btrfs_key *first_key)
> + struct btrfs_tree_parent_check *check)
> {
> struct btrfs_fs_info *fs_info = eb->fs_info;
> struct extent_io_tree *io_tree;
> @@ -269,16 +267,20 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
> int mirror_num = 0;
> int failed_mirror = 0;
>
> + ASSERT(check);
> +
> io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
> while (1) {
> clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
> ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num);
> if (!ret) {
> if (verify_parent_transid(io_tree, eb,
> - parent_transid, 0))
> + check->transid, 0))
> ret = -EIO;
> - else if (btrfs_verify_level_key(eb, level,
> - first_key, parent_transid))
> + else if (btrfs_verify_level_key(eb, check->level,
> + check->has_first_key ?
> + &check->first_key : NULL,
> + check->transid))
> ret = -EUCLEAN;
> else
> break;
> @@ -922,28 +924,28 @@ struct extent_buffer *btrfs_find_create_tree_block(
> * Read tree block at logical address @bytenr and do variant basic but critical
> * verification.
> *
> - * @owner_root: the objectid of the root owner for this block.
> - * @parent_transid: expected transid of this tree block, skip check if 0
> - * @level: expected level, mandatory check
> - * @first_key: expected key in slot 0, skip check if NULL
> + * @check: expected tree parentness check, see comments of the
> + * structure for details.
> */
> struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
> - u64 owner_root, u64 parent_transid,
> - int level, struct btrfs_key *first_key)
> + struct btrfs_tree_parent_check *check)
> {
> struct extent_buffer *buf = NULL;
> int ret;
>
> - buf = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
> + ASSERT(check);
> +
> + buf = btrfs_find_create_tree_block(fs_info, bytenr, check->owner_root,
> + check->level);
> if (IS_ERR(buf))
> return buf;
>
> - ret = btrfs_read_extent_buffer(buf, parent_transid, level, first_key);
> + ret = btrfs_read_extent_buffer(buf, check);
> if (ret) {
> free_extent_buffer_stale(buf);
> return ERR_PTR(ret);
> }
> - if (btrfs_check_eb_owner(buf, owner_root)) {
> + if (btrfs_check_eb_owner(buf, check->owner_root)) {
> free_extent_buffer_stale(buf);
> return ERR_PTR(-EUCLEAN);
> }
> @@ -1355,6 +1357,7 @@ static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,
> struct btrfs_key *key)
> {
> struct btrfs_root *root;
> + struct btrfs_tree_parent_check check = {0};
> struct btrfs_fs_info *fs_info = tree_root->fs_info;
> u64 generation;
> int ret;
> @@ -1374,9 +1377,12 @@ static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,
>
> generation = btrfs_root_generation(&root->root_item);
> level = btrfs_root_level(&root->root_item);
> + check.level = level;
> + check.transid = generation;
> + check.owner_root = key->objectid;
> root->node = read_tree_block(fs_info,
> btrfs_root_bytenr(&root->root_item),
> - key->objectid, generation, level, NULL);
> + &check);
> if (IS_ERR(root->node)) {
> ret = PTR_ERR(root->node);
> root->node = NULL;
> @@ -2351,6 +2357,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
> struct btrfs_fs_devices *fs_devices)
> {
> int ret;
> + struct btrfs_tree_parent_check check = {0};
> struct btrfs_root *log_tree_root;
> struct btrfs_super_block *disk_super = fs_info->super_copy;
> u64 bytenr = btrfs_super_log_root(disk_super);
> @@ -2366,10 +2373,10 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
> if (!log_tree_root)
> return -ENOMEM;
>
> - log_tree_root->node = read_tree_block(fs_info, bytenr,
> - BTRFS_TREE_LOG_OBJECTID,
> - fs_info->generation + 1, level,
> - NULL);
> + check.level = level;
> + check.transid = fs_info->generation + 1;
> + check.owner_root = BTRFS_TREE_LOG_OBJECTID;
> + log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
> if (IS_ERR(log_tree_root->node)) {
> btrfs_warn(fs_info, "failed to read log tree");
> ret = PTR_ERR(log_tree_root->node);
> @@ -2845,10 +2852,14 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info,
>
> static int load_super_root(struct btrfs_root *root, u64 bytenr, u64 gen, int level)
> {
> + struct btrfs_tree_parent_check check = {0};
> int ret = 0;
>
> - root->node = read_tree_block(root->fs_info, bytenr,
> - root->root_key.objectid, gen, level, NULL);
> + check.level = level;
> + check.transid = gen;
> + check.owner_root = root->root_key.objectid;
In some cases where the initialization parameters are simple I've moved
it to the definition of block like
struct btrfs_tree_parent_check check = {
.level = level,
.transid = gen,
.owner_root = root->root_key.objectid
};
next prev parent reply other threads:[~2022-11-11 16:10 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-14 5:32 [PATCH 0/2] btrfs: do most metadata parentnesss check at endio time Qu Wenruo
2022-09-14 5:32 ` [PATCH 1/2] btrfs: concentrate all tree block parentness check parameters into one structure Qu Wenruo
2022-11-11 16:09 ` David Sterba [this message]
2022-09-14 5:32 ` [PATCH 2/2] btrfs: move tree block parentness check into validate_extent_buffer() Qu Wenruo
2022-11-11 16:07 ` [PATCH 0/2] btrfs: do most metadata parentnesss check at endio time David Sterba
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=20221111160957.GU5824@twin.jikos.cz \
--to=dsterba@suse.cz \
--cc=linux-btrfs@vger.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