Skip to content

Commit

Permalink
btrfs: assert delayed node locked when removing delayed item
Browse files Browse the repository at this point in the history
[ Upstream commit a57c2d4 ]

When removing a delayed item, or releasing which will remove it as well,
we will modify one of the delayed node's rbtrees and item counter if the
delayed item is in one of the rbtrees. This require having the delayed
node's mutex locked, otherwise we will race with other tasks modifying
the rbtrees and the counter.

This is motivated by a previous version of another patch actually calling
btrfs_release_delayed_item() after unlocking the delayed node's mutex and
against a delayed item that is in a rbtree.

So assert at __btrfs_remove_delayed_item() that the delayed node's mutex
is locked.

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
fdmanana authored and gregkh committed Oct 6, 2023
1 parent 11054f0 commit 45ad79c
Showing 1 changed file with 8 additions and 4 deletions.
12 changes: 8 additions & 4 deletions fs/btrfs/delayed-inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,25 +407,29 @@ static void finish_one_item(struct btrfs_delayed_root *delayed_root)

static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)
{
struct btrfs_delayed_node *delayed_node = delayed_item->delayed_node;
struct rb_root_cached *root;
struct btrfs_delayed_root *delayed_root;

/* Not inserted, ignore it. */
if (RB_EMPTY_NODE(&delayed_item->rb_node))
return;

delayed_root = delayed_item->delayed_node->root->fs_info->delayed_root;
/* If it's in a rbtree, then we need to have delayed node locked. */
lockdep_assert_held(&delayed_node->mutex);

delayed_root = delayed_node->root->fs_info->delayed_root;

BUG_ON(!delayed_root);

if (delayed_item->type == BTRFS_DELAYED_INSERTION_ITEM)
root = &delayed_item->delayed_node->ins_root;
root = &delayed_node->ins_root;
else
root = &delayed_item->delayed_node->del_root;
root = &delayed_node->del_root;

rb_erase_cached(&delayed_item->rb_node, root);
RB_CLEAR_NODE(&delayed_item->rb_node);
delayed_item->delayed_node->count--;
delayed_node->count--;

finish_one_item(delayed_root);
}
Expand Down

0 comments on commit 45ad79c

Please sign in to comment.