From: Josef Bacik <josef@toxicpanda.com>
To: linux-btrfs@vger.kernel.org, kernel-team@fb.com
Subject: [PATCH v3 08/15] btrfs: extract the reference dropping code into it's own helper
Date: Tue, 7 May 2024 14:12:09 -0400 [thread overview]
Message-ID: <f6907b7026ebac0e7226af2e2ede21d7dec5b4db.1715105406.git.josef@toxicpanda.com> (raw)
In-Reply-To: <cover.1715105406.git.josef@toxicpanda.com>
This is a big chunk of code in do_walk_down that will conditionally
remove the reference for the child block we're currently evaluating.
Extract it out into it's own helper and call that from do_walk_down
instead.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/extent-tree.c | 162 +++++++++++++++++++++++------------------
1 file changed, 92 insertions(+), 70 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 4c6647760aa5..bf59e2f00ff8 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5509,6 +5509,95 @@ static int check_next_block_uptodate(struct btrfs_trans_handle *trans,
return 0;
}
+/*
+ * If we determine that we don't have to visit wc->level - 1 then we need to
+ * determine if we can drop our reference.
+ *
+ * If we are UPDATE_BACKREF then we will not, we need to update our backrefs.
+ *
+ * If we are DROP_REFERENCE this will figure out if we need to drop our current
+ * reference, skipping it if we dropped it from a previous incompleted drop, or
+ * dropping it if we still have a reference to it.
+ */
+static int maybe_drop_reference(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct walk_control *wc,
+ struct extent_buffer *next,
+ u64 owner_root)
+{
+ struct btrfs_ref ref = {
+ .action = BTRFS_DROP_DELAYED_REF,
+ .bytenr = next->start,
+ .num_bytes = root->fs_info->nodesize,
+ .owning_root = owner_root,
+ .ref_root = btrfs_root_id(root),
+ };
+ int level = wc->level;
+ int ret;
+
+ /* We are UPDATE_BACKREF, we're not dropping anything. */
+ if (wc->stage == UPDATE_BACKREF)
+ return 0;
+
+ if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
+ ref.parent = path->nodes[level]->start;
+ } else {
+ ASSERT(btrfs_root_id(root) ==
+ btrfs_header_owner(path->nodes[level]));
+ if (btrfs_root_id(root) !=
+ btrfs_header_owner(path->nodes[level])) {
+ btrfs_err(root->fs_info,
+ "mismatched block owner");
+ return -EIO;
+ }
+ }
+
+ /*
+ * If we had a drop_progress we need to verify the refs are set as
+ * expected. If we find our ref then we know that from here on out
+ * everything should be correct, and we can clear the
+ * ->restarted flag.
+ */
+ if (wc->restarted) {
+ ret = check_ref_exists(trans, root, next->start, ref.parent,
+ level - 1);
+ if (ret <= 0)
+ return ret;
+ ret = 0;
+ wc->restarted = 0;
+ }
+
+ /*
+ * Reloc tree doesn't contribute to qgroup numbers, and we have already
+ * accounted them at merge time (replace_path), thus we could skip
+ * expensive subtree trace here.
+ */
+ if (btrfs_root_id(root) != BTRFS_TREE_RELOC_OBJECTID &&
+ wc->refs[level - 1] > 1) {
+ u64 generation = btrfs_node_ptr_generation(path->nodes[level],
+ path->slots[level]);
+
+ ret = btrfs_qgroup_trace_subtree(trans, next, generation, level - 1);
+ if (ret) {
+ btrfs_err_rl(root->fs_info,
+ "Error %d accounting shared subtree. Quota is out of sync, rescan required.",
+ ret);
+ }
+ }
+
+ /*
+ * We need to update the next key in our walk control so we can
+ * update the drop_progress key accordingly. We don't care if
+ * find_next_key doesn't find a key because that means we're at
+ * the end and are going to clean up now.
+ */
+ wc->drop_level = level;
+ find_next_key(path, level, &wc->drop_progress);
+
+ btrfs_init_tree_ref(&ref, level - 1, 0, false);
+ return btrfs_free_extent(trans, &ref);
+}
/*
* helper to process tree block pointer.
@@ -5607,76 +5696,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
wc->reada_slot = 0;
return 0;
skip:
- if (wc->stage == DROP_REFERENCE) {
- struct btrfs_ref ref = {
- .action = BTRFS_DROP_DELAYED_REF,
- .bytenr = bytenr,
- .num_bytes = fs_info->nodesize,
- .owning_root = owner_root,
- .ref_root = btrfs_root_id(root),
- };
- if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
- ref.parent = path->nodes[level]->start;
- } else {
- ASSERT(btrfs_root_id(root) ==
- btrfs_header_owner(path->nodes[level]));
- if (btrfs_root_id(root) !=
- btrfs_header_owner(path->nodes[level])) {
- btrfs_err(root->fs_info,
- "mismatched block owner");
- ret = -EIO;
- goto out_unlock;
- }
- }
-
- /*
- * If we had a drop_progress we need to verify the refs are set
- * as expected. If we find our ref then we know that from here
- * on out everything should be correct, and we can clear the
- * ->restarted flag.
- */
- if (wc->restarted) {
- ret = check_ref_exists(trans, root, bytenr, ref.parent,
- level - 1);
- if (ret < 0)
- goto out_unlock;
- if (ret == 0)
- goto no_delete;
- ret = 0;
- wc->restarted = 0;
- }
-
- /*
- * Reloc tree doesn't contribute to qgroup numbers, and we have
- * already accounted them at merge time (replace_path),
- * thus we could skip expensive subtree trace here.
- */
- if (btrfs_root_id(root) != BTRFS_TREE_RELOC_OBJECTID &&
- wc->refs[level - 1] > 1) {
- ret = btrfs_qgroup_trace_subtree(trans, next,
- generation, level - 1);
- if (ret) {
- btrfs_err_rl(fs_info,
- "Error %d accounting shared subtree. Quota is out of sync, rescan required.",
- ret);
- }
- }
-
- /*
- * We need to update the next key in our walk control so we can
- * update the drop_progress key accordingly. We don't care if
- * find_next_key doesn't find a key because that means we're at
- * the end and are going to clean up now.
- */
- wc->drop_level = level;
- find_next_key(path, level, &wc->drop_progress);
-
- btrfs_init_tree_ref(&ref, level - 1, 0, false);
- ret = btrfs_free_extent(trans, &ref);
- if (ret)
- goto out_unlock;
- }
-no_delete:
+ ret = maybe_drop_reference(trans, root, path, wc, next, owner_root);
+ if (ret)
+ goto out_unlock;
wc->refs[level - 1] = 0;
wc->flags[level - 1] = 0;
wc->lookup_info = 1;
--
2.43.0
next prev parent reply other threads:[~2024-05-07 18:12 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-07 18:12 [PATCH v3 00/15] btrfs: snapshot delete cleanups Josef Bacik
2024-05-07 18:12 ` [PATCH v3 01/15] btrfs: don't do find_extent_buffer in do_walk_down Josef Bacik
2024-05-07 18:12 ` [PATCH v3 02/15] btrfs: remove all extra btrfs_check_eb_owner() calls Josef Bacik
2024-05-07 20:39 ` Qu Wenruo
2024-05-07 18:12 ` [PATCH v3 03/15] btrfs: use btrfs_read_extent_buffer in do_walk_down Josef Bacik
2024-05-07 18:12 ` [PATCH v3 04/15] btrfs: push lookup_info into walk_control Josef Bacik
2024-05-07 18:12 ` [PATCH v3 05/15] btrfs: move the eb uptodate code into it's own helper Josef Bacik
2024-05-07 18:12 ` [PATCH v3 06/15] btrfs: remove need_account in do_walk_down Josef Bacik
2024-05-07 18:12 ` [PATCH v3 07/15] btrfs: unify logic to decide if we need to walk down into a node Josef Bacik
2024-05-07 18:12 ` Josef Bacik [this message]
2024-05-07 18:12 ` [PATCH v3 09/15] btrfs: don't BUG_ON ENOMEM in walk_down_proc Josef Bacik
2024-05-07 18:12 ` [PATCH v3 10/15] btrfs: handle errors from ref mods during UPDATE_BACKREF Josef Bacik
2024-05-07 18:12 ` [PATCH v3 11/15] btrfs: replace BUG_ON with ASSERT in walk_down_proc Josef Bacik
2024-05-07 18:12 ` [PATCH v3 12/15] btrfs: clean up our handling of refs == 0 in snapshot delete Josef Bacik
2024-05-07 18:12 ` [PATCH v3 13/15] btrfs: convert correctness BUG_ON()'s to ASSERT()'s in walk_up_proc Josef Bacik
2024-05-07 18:12 ` [PATCH v3 14/15] btrfs: handle errors from btrfs_dec_ref properly Josef Bacik
2024-05-07 18:12 ` [PATCH v3 15/15] btrfs: add documentation around snapshot delete Josef Bacik
2024-05-15 18:18 ` [PATCH v3 00/15] btrfs: snapshot delete cleanups 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=f6907b7026ebac0e7226af2e2ede21d7dec5b4db.1715105406.git.josef@toxicpanda.com \
--to=josef@toxicpanda.com \
--cc=kernel-team@fb.com \
--cc=linux-btrfs@vger.kernel.org \
/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;
as well as URLs for NNTP newsgroup(s).