diff options
author | Filipe Manana <fdmanana@suse.com> | 2024-10-21 12:40:08 +0100 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2024-11-11 14:34:20 +0100 |
commit | a98048e10d44569b8d5ba6edcb20992cf57ed816 (patch) | |
tree | a69479a33be2863fabd9202641faf10ca5fd8c1b /fs/btrfs/delayed-ref.c | |
parent | 7ef360488600e8b7c131306b9f5ed7e42202b487 (diff) | |
download | lwn-a98048e10d44569b8d5ba6edcb20992cf57ed816.tar.gz lwn-a98048e10d44569b8d5ba6edcb20992cf57ed816.zip |
btrfs: simplify obtaining a delayed ref head
Instead of doing it in two steps outside of delayed-ref.c, leaking low
level details such as locking, move the logic entirely to delayed-ref.c
under btrfs_select_ref_head(), reducing code and making things simpler
for the caller.
Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/delayed-ref.c')
-rw-r--r-- | fs/btrfs/delayed-ref.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 8392cb366700..fdecdd02db94 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -431,8 +431,8 @@ static struct btrfs_delayed_ref_head *find_ref_head( return NULL; } -bool btrfs_delayed_ref_lock(struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_head *head) +static bool btrfs_delayed_ref_lock(struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_head *head) { lockdep_assert_held(&delayed_refs->lock); if (mutex_trylock(&head->mutex)) @@ -561,8 +561,9 @@ struct btrfs_delayed_ref_head *btrfs_select_ref_head( struct btrfs_delayed_ref_root *delayed_refs) { struct btrfs_delayed_ref_head *head; + bool locked; - lockdep_assert_held(&delayed_refs->lock); + spin_lock(&delayed_refs->lock); again: head = find_ref_head(delayed_refs, delayed_refs->run_delayed_start, true); @@ -570,16 +571,20 @@ again: delayed_refs->run_delayed_start = 0; head = find_first_ref_head(delayed_refs); } - if (!head) + if (!head) { + spin_unlock(&delayed_refs->lock); return NULL; + } while (head->processing) { struct rb_node *node; node = rb_next(&head->href_node); if (!node) { - if (delayed_refs->run_delayed_start == 0) + if (delayed_refs->run_delayed_start == 0) { + spin_unlock(&delayed_refs->lock); return NULL; + } delayed_refs->run_delayed_start = 0; goto again; } @@ -592,6 +597,18 @@ again: delayed_refs->num_heads_ready--; delayed_refs->run_delayed_start = head->bytenr + head->num_bytes; + + locked = btrfs_delayed_ref_lock(delayed_refs, head); + spin_unlock(&delayed_refs->lock); + + /* + * We may have dropped the spin lock to get the head mutex lock, and + * that might have given someone else time to free the head. If that's + * true, it has been removed from our list and we can move on. + */ + if (!locked) + return ERR_PTR(-EAGAIN); + return head; } |