From: fdmanana@kernel.org
To: linux-btrfs@vger.kernel.org
Subject: [PATCH 10/22] btrfs: avoid unnecessary next node searches when clearing bits from extent range
Date: Wed, 23 Apr 2025 15:19:50 +0100 [thread overview]
Message-ID: <73d68a9cbf6944f14cb87936bfce3eefea3e2a74.1745401628.git.fdmanana@suse.com> (raw)
In-Reply-To: <cover.1745401627.git.fdmanana@suse.com>
From: Filipe Manana <fdmanana@suse.com>
When clearing bits for a range in an io tree, at clear_state_bit(), we
always go search for the next node (through next_state() -> rb_next()) and
return it. However if the current extent state record ends at or after the
target range passed to btrfs_clear_extent_bit_changeset() or
btrfs_convert_extent_bit(), we are just wasting time finding that next
node since we won't use it in those functions.
Improve on this by skipping the next node search if the current node ends
at or after the target range.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
fs/btrfs/extent-io-tree.c | 41 ++++++++++++++++++++++++++-------------
1 file changed, 28 insertions(+), 13 deletions(-)
diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c
index 591111879aec..bb829c5703f2 100644
--- a/fs/btrfs/extent-io-tree.c
+++ b/fs/btrfs/extent-io-tree.c
@@ -544,12 +544,9 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
* If no bits are set on the state struct after clearing things, the
* struct is freed and removed from the tree
*/
-static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
- struct extent_state *state,
- u32 bits, int wake,
- struct extent_changeset *changeset)
+static void clear_state_bit(struct extent_io_tree *tree, struct extent_state *state,
+ u32 bits, int wake, struct extent_changeset *changeset)
{
- struct extent_state *next;
u32 bits_to_clear = bits & ~EXTENT_CTLBITS;
int ret;
@@ -562,7 +559,6 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
if (wake)
wake_up(&state->wq);
if (state->state == 0) {
- next = next_state(state);
if (extent_state_in_tree(state)) {
rb_erase(&state->rb_node, &tree->state);
RB_CLEAR_NODE(&state->rb_node);
@@ -572,9 +568,7 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
}
} else {
merge_state(tree, state);
- next = next_state(state);
}
- return next;
}
/*
@@ -587,6 +581,18 @@ static void set_gfp_mask_from_bits(u32 *bits, gfp_t *mask)
*bits &= EXTENT_NOWAIT - 1;
}
+/*
+ * Use this during tree iteration to avoid doing next node searches when it's
+ * not needed (the current record ends at or after the target range's end).
+ */
+static inline struct extent_state *next_search_state(struct extent_state *state, u64 end)
+{
+ if (state->end < end)
+ return next_state(state);
+
+ return NULL;
+}
+
/*
* Clear some bits on a range in the tree. This may require splitting or
* inserting elements in the tree, so the gfp mask is used to indicate which
@@ -601,6 +607,7 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64
struct extent_changeset *changeset)
{
struct extent_state *state;
+ struct extent_state *next;
struct extent_state *cached;
struct extent_state *prealloc = NULL;
u64 last_end;
@@ -666,7 +673,7 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64
/* The state doesn't have the wanted bits, go ahead. */
if (!(state->state & bits)) {
- state = next_state(state);
+ next = next_search_state(state, end);
goto next;
}
@@ -696,7 +703,8 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64
goto out;
}
if (state->end <= end) {
- state = clear_state_bit(tree, state, bits, wake, changeset);
+ next = next_search_state(state, end);
+ clear_state_bit(tree, state, bits, wake, changeset);
goto next;
}
if (need_resched())
@@ -732,11 +740,13 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64
goto out;
}
- state = clear_state_bit(tree, state, bits, wake, changeset);
+ next = next_search_state(state, end);
+ clear_state_bit(tree, state, bits, wake, changeset);
next:
if (last_end >= end)
goto out;
start = last_end + 1;
+ state = next;
if (state && !need_resched())
goto hit_next;
@@ -1292,6 +1302,7 @@ int btrfs_convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached_state)
{
struct extent_state *state;
+ struct extent_state *next;
struct extent_state *prealloc = NULL;
struct rb_node **p = NULL;
struct rb_node *parent = NULL;
@@ -1357,10 +1368,12 @@ int btrfs_convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->start == start && state->end <= end) {
set_state_bits(tree, state, bits, NULL);
cache_state(state, cached_state);
- state = clear_state_bit(tree, state, clear_bits, 0, NULL);
+ next = next_search_state(state, end);
+ clear_state_bit(tree, state, clear_bits, 0, NULL);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
+ state = next;
if (start < end && state && state->start == start &&
!need_resched())
goto hit_next;
@@ -1397,10 +1410,12 @@ int btrfs_convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->end <= end) {
set_state_bits(tree, state, bits, NULL);
cache_state(state, cached_state);
- state = clear_state_bit(tree, state, clear_bits, 0, NULL);
+ next = next_search_state(state, end);
+ clear_state_bit(tree, state, clear_bits, 0, NULL);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
+ state = next;
if (start < end && state && state->start == start &&
!need_resched())
goto hit_next;
--
2.47.2
next prev parent reply other threads:[~2025-04-23 14:20 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-23 14:19 [PATCH 00/22] btrfs: some io tree optimizations and cleanups fdmanana
2025-04-23 14:19 ` [PATCH 01/22] btrfs: remove duplicate error check at btrfs_clear_extent_bit_changeset() fdmanana
2025-04-23 14:19 ` [PATCH 02/22] btrfs: exit after state split error " fdmanana
2025-04-23 14:19 ` [PATCH 03/22] btrfs: add missing error return to btrfs_clear_extent_bit_changeset() fdmanana
2025-04-23 14:19 ` [PATCH 04/22] btrfs: use bools for local variables at btrfs_clear_extent_bit_changeset() fdmanana
2025-04-23 14:19 ` [PATCH 05/22] btrfs: avoid extra tree search " fdmanana
2025-04-23 14:19 ` [PATCH 06/22] btrfs: simplify last record detection " fdmanana
2025-04-23 14:19 ` [PATCH 07/22] btrfs: remove duplicate error check at btrfs_convert_extent_bit() fdmanana
2025-04-23 14:19 ` [PATCH 08/22] btrfs: exit after state split error " fdmanana
2025-04-23 14:19 ` [PATCH 09/22] btrfs: exit after state insertion failure " fdmanana
2025-04-23 14:19 ` fdmanana [this message]
2025-04-23 14:19 ` [PATCH 11/22] btrfs: avoid repeated extent state processing when converting extent bits fdmanana
2025-04-23 14:19 ` [PATCH 12/22] btrfs: avoid researching tree when converting bits in an extent range fdmanana
2025-04-23 14:19 ` [PATCH 13/22] btrfs: simplify last record detection at btrfs_convert_extent_bit() fdmanana
2025-04-23 14:19 ` [PATCH 14/22] btrfs: exit after state insertion failure at set_extent_bit() fdmanana
2025-04-23 14:19 ` [PATCH 15/22] btrfs: exit after state split error " fdmanana
2025-04-23 14:19 ` [PATCH 16/22] btrfs: simplify last record detection " fdmanana
2025-04-23 14:19 ` [PATCH 17/22] btrfs: avoid repeated extent state processing when setting extent bits fdmanana
2025-04-23 14:19 ` [PATCH 18/22] btrfs: avoid researching tree when setting bits in an extent range fdmanana
2025-04-23 14:19 ` [PATCH 19/22] btrfs: remove unnecessary NULL checks before freeing extent state fdmanana
2025-04-23 14:20 ` [PATCH 20/22] btrfs: don't BUG_ON() when unpinning extents during transaction commit fdmanana
2025-04-23 14:20 ` [PATCH 21/22] btrfs: remove variable to track trimmed bytes at btrfs_finish_extent_commit() fdmanana
2025-04-23 14:20 ` [PATCH 22/22] btrfs: make extent unpinning more efficient when committing transaction fdmanana
2025-04-28 14:53 ` [PATCH 00/22] btrfs: some io tree optimizations and 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=73d68a9cbf6944f14cb87936bfce3eefea3e2a74.1745401628.git.fdmanana@suse.com \
--to=fdmanana@kernel.org \
--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