From: Filipe Manana Date: Wed, 11 Mar 2026 15:07:11 +0000 (+0000) Subject: btrfs: avoid unnecessary wake ups on io trees when there are no waiters X-Git-Tag: v7.1-rc1~231^2~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87f5c3139ee34e0642584cff86298ef4b9a827ef;p=thirdparty%2Fkernel%2Flinux.git btrfs: avoid unnecessary wake ups on io trees when there are no waiters Whenever clearing the extent lock bits of an extent state record, we unconditionally call wake_up() on the state's waitqueue. Most of the time there are no waiters on the queue so we are just wasting time calling wake_up(), since that requires locking and unlocking the queue's spinlock, disable and re-enable interrupts, function calls, and other minor overhead while we are holding a critical section delimited by the extent io tree's spinlock. So call wake_up() only if there are waiters on an extent state's wait queue. Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c index 5ffb99c258e9a..0d9437e72bd4f 100644 --- a/fs/btrfs/extent-io-tree.c +++ b/fs/btrfs/extent-io-tree.c @@ -536,6 +536,24 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, return 0; } +static inline void state_wake_up(struct extent_io_tree *tree, + struct extent_state *state, u32 bits) +{ + lockdep_assert_held(&tree->lock); + + if (!(bits & EXTENT_LOCK_BITS)) + return; + + /* + * No memory barriers because the tree's lock is held while: + * + * 1) Adding waiters to the queue. + * 2) Waking up waiters. + * 3) Removing waiters from queue. + */ + cond_wake_up_nomb(&state->wq); +} + /* * 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). @@ -571,8 +589,7 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree, if (unlikely(ret)) extent_io_tree_panic(tree, state, "add_extent_changeset", ret); state->state &= ~bits_to_clear; - if (bits & EXTENT_LOCK_BITS) - wake_up(&state->wq); + state_wake_up(tree, state, bits); if (state->state == 0) { next = next_search_state(state, end); if (extent_state_in_tree(state)) { @@ -618,7 +635,6 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64 u64 last_end; int ret = 0; bool clear; - bool wake; const bool delete = (bits & EXTENT_CLEAR_ALL_BITS); gfp_t mask; @@ -632,7 +648,6 @@ int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64 if (bits & EXTENT_DELALLOC) bits |= EXTENT_NORESERVE; - wake = (bits & EXTENT_LOCK_BITS); clear = (bits & (EXTENT_LOCK_BITS | EXTENT_BOUNDARY)); again: if (!prealloc) { @@ -758,8 +773,7 @@ hit_next: state->start = end + 1; state->end = orig_end; - if (wake) - wake_up(&state->wq); + state_wake_up(tree, state, bits); goto out; } @@ -773,8 +787,7 @@ hit_next: goto out; } - if (wake) - wake_up(&state->wq); + state_wake_up(tree, state, bits); clear_state_bit(tree, prealloc, bits, end, changeset);