Commit b769777d authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: use refcount_t type for the extent buffer reference counter



Instead of using a bare atomic, use the refcount_t type, which despite
being a structure that contains only an atomic, has an API that checks
for underflows and other hazards. This doesn't change the size of the
extent_buffer structure.

This removes the need to do things like this:

    WARN_ON(atomic_read(&eb->refs) == 0);
    if (atomic_dec_and_test(&eb->refs)) {
        (...)
    }

And do just:

    if (refcount_dec_and_test(&eb->refs)) {
        (...)
    }

Since refcount_dec_and_test() already triggers a warning when we decrement
a ref count that has a value of 0 (or below zero).

Reviewed-by: default avatarBoris Burkov <boris@bur.io>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 2697b615
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -198,7 +198,7 @@ struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
		 * the inc_not_zero dance and if it doesn't work then
		 * synchronize_rcu and try again.
		 */
		if (atomic_inc_not_zero(&eb->refs)) {
		if (refcount_inc_not_zero(&eb->refs)) {
			rcu_read_unlock();
			break;
		}
@@ -560,7 +560,7 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
			btrfs_abort_transaction(trans, ret);
			goto error_unlock_cow;
		}
		atomic_inc(&cow->refs);
		refcount_inc(&cow->refs);
		rcu_assign_pointer(root->node, cow);

		ret = btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
@@ -1092,7 +1092,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
	/* update the path */
	if (left) {
		if (btrfs_header_nritems(left) > orig_slot) {
			atomic_inc(&left->refs);
			refcount_inc(&left->refs);
			/* left was locked after cow */
			path->nodes[level] = left;
			path->slots[level + 1] -= 1;
@@ -1696,7 +1696,7 @@ static struct extent_buffer *btrfs_search_slot_get_root(struct btrfs_root *root,

	if (p->search_commit_root) {
		b = root->commit_root;
		atomic_inc(&b->refs);
		refcount_inc(&b->refs);
		level = btrfs_header_level(b);
		/*
		 * Ensure that all callers have set skip_locking when
@@ -2894,7 +2894,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
	free_extent_buffer(old);

	add_root_to_dirty_list(root);
	atomic_inc(&c->refs);
	refcount_inc(&c->refs);
	path->nodes[level] = c;
	path->locks[level] = BTRFS_WRITE_LOCK;
	path->slots[level] = 0;
@@ -4451,7 +4451,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,

	root_sub_used_bytes(root);

	atomic_inc(&leaf->refs);
	refcount_inc(&leaf->refs);
	ret = btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
	free_extent_buffer_stale(leaf);
	if (ret < 0)
@@ -4536,7 +4536,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
			 * for possible call to btrfs_del_ptr below
			 */
			slot = path->slots[1];
			atomic_inc(&leaf->refs);
			refcount_inc(&leaf->refs);
			/*
			 * We want to be able to at least push one item to the
			 * left neighbour leaf, and that's the first item.
+1 −1
Original line number Diff line number Diff line
@@ -6348,7 +6348,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,

	btrfs_assert_tree_write_locked(parent);
	parent_level = btrfs_header_level(parent);
	atomic_inc(&parent->refs);
	refcount_inc(&parent->refs);
	path->nodes[parent_level] = parent;
	path->slots[parent_level] = btrfs_header_nritems(parent);

+22 −23
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ void btrfs_extent_buffer_leak_debug_check(struct btrfs_fs_info *fs_info)
				      struct extent_buffer, leak_list);
		pr_err(
	"BTRFS: buffer leak start %llu len %u refs %d bflags %lu owner %llu\n",
		       eb->start, eb->len, atomic_read(&eb->refs), eb->bflags,
		       eb->start, eb->len, refcount_read(&eb->refs), eb->bflags,
		       btrfs_header_owner(eb));
		list_del(&eb->leak_list);
		WARN_ON_ONCE(1);
@@ -1961,7 +1961,7 @@ static inline struct extent_buffer *find_get_eb(struct xa_state *xas, unsigned l
	if (!eb)
		return NULL;

	if (!atomic_inc_not_zero(&eb->refs)) {
	if (!refcount_inc_not_zero(&eb->refs)) {
		xas_reset(xas);
		goto retry;
	}
@@ -2012,7 +2012,7 @@ static struct extent_buffer *find_extent_buffer_nolock(

	rcu_read_lock();
	eb = xa_load(&fs_info->buffer_tree, index);
	if (eb && !atomic_inc_not_zero(&eb->refs))
	if (eb && !refcount_inc_not_zero(&eb->refs))
		eb = NULL;
	rcu_read_unlock();
	return eb;
@@ -2842,7 +2842,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct btrfs_fs_info *fs_info
	btrfs_leak_debug_add_eb(eb);

	spin_lock_init(&eb->refs_lock);
	atomic_set(&eb->refs, 1);
	refcount_set(&eb->refs, 1);

	ASSERT(eb->len <= BTRFS_MAX_METADATA_BLOCKSIZE);

@@ -2975,13 +2975,13 @@ static void check_buffer_tree_ref(struct extent_buffer *eb)
	 * once io is initiated, TREE_REF can no longer be cleared, so that is
	 * the moment at which any such race is best fixed.
	 */
	refs = atomic_read(&eb->refs);
	refs = refcount_read(&eb->refs);
	if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
		return;

	spin_lock(&eb->refs_lock);
	if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
		atomic_inc(&eb->refs);
		refcount_inc(&eb->refs);
	spin_unlock(&eb->refs_lock);
}

@@ -3047,7 +3047,7 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
		return ERR_PTR(ret);
	}
	if (exists) {
		if (!atomic_inc_not_zero(&exists->refs)) {
		if (!refcount_inc_not_zero(&exists->refs)) {
			/* The extent buffer is being freed, retry. */
			xa_unlock_irq(&fs_info->buffer_tree);
			goto again;
@@ -3092,7 +3092,7 @@ static struct extent_buffer *grab_extent_buffer(struct btrfs_fs_info *fs_info,
	 * just overwrite folio private.
	 */
	exists = folio_get_private(folio);
	if (atomic_inc_not_zero(&exists->refs))
	if (refcount_inc_not_zero(&exists->refs))
		return exists;

	WARN_ON(folio_test_dirty(folio));
@@ -3362,7 +3362,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
		goto out;
	}
	if (existing_eb) {
		if (!atomic_inc_not_zero(&existing_eb->refs)) {
		if (!refcount_inc_not_zero(&existing_eb->refs)) {
			xa_unlock_irq(&fs_info->buffer_tree);
			goto again;
		}
@@ -3391,7 +3391,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
	return eb;

out:
	WARN_ON(!atomic_dec_and_test(&eb->refs));
	WARN_ON(!refcount_dec_and_test(&eb->refs));

	/*
	 * Any attached folios need to be detached before we unlock them.  This
@@ -3437,8 +3437,7 @@ static int release_extent_buffer(struct extent_buffer *eb)
{
	lockdep_assert_held(&eb->refs_lock);

	WARN_ON(atomic_read(&eb->refs) == 0);
	if (atomic_dec_and_test(&eb->refs)) {
	if (refcount_dec_and_test(&eb->refs)) {
		struct btrfs_fs_info *fs_info = eb->fs_info;

		spin_unlock(&eb->refs_lock);
@@ -3484,7 +3483,7 @@ void free_extent_buffer(struct extent_buffer *eb)
	if (!eb)
		return;

	refs = atomic_read(&eb->refs);
	refs = refcount_read(&eb->refs);
	while (1) {
		if (test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags)) {
			if (refs == 1)
@@ -3494,16 +3493,16 @@ void free_extent_buffer(struct extent_buffer *eb)
		}

		/* Optimization to avoid locking eb->refs_lock. */
		if (atomic_try_cmpxchg(&eb->refs, &refs, refs - 1))
		if (atomic_try_cmpxchg(&eb->refs.refs, &refs, refs - 1))
			return;
	}

	spin_lock(&eb->refs_lock);
	if (atomic_read(&eb->refs) == 2 &&
	if (refcount_read(&eb->refs) == 2 &&
	    test_bit(EXTENT_BUFFER_STALE, &eb->bflags) &&
	    !extent_buffer_under_io(eb) &&
	    test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
		atomic_dec(&eb->refs);
		refcount_dec(&eb->refs);

	/*
	 * I know this is terrible, but it's temporary until we stop tracking
@@ -3520,9 +3519,9 @@ void free_extent_buffer_stale(struct extent_buffer *eb)
	spin_lock(&eb->refs_lock);
	set_bit(EXTENT_BUFFER_STALE, &eb->bflags);

	if (atomic_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) &&
	if (refcount_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) &&
	    test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
		atomic_dec(&eb->refs);
		refcount_dec(&eb->refs);
	release_extent_buffer(eb);
}

@@ -3580,7 +3579,7 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
			btree_clear_folio_dirty_tag(folio);
		folio_unlock(folio);
	}
	WARN_ON(atomic_read(&eb->refs) == 0);
	WARN_ON(refcount_read(&eb->refs) == 0);
}

void set_extent_buffer_dirty(struct extent_buffer *eb)
@@ -3591,7 +3590,7 @@ void set_extent_buffer_dirty(struct extent_buffer *eb)

	was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);

	WARN_ON(atomic_read(&eb->refs) == 0);
	WARN_ON(refcount_read(&eb->refs) == 0);
	WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags));
	WARN_ON(test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags));

@@ -3717,7 +3716,7 @@ int read_extent_buffer_pages_nowait(struct extent_buffer *eb, int mirror_num,

	eb->read_mirror = 0;
	check_buffer_tree_ref(eb);
	atomic_inc(&eb->refs);
	refcount_inc(&eb->refs);

	bbio = btrfs_bio_alloc(INLINE_EXTENT_BUFFER_PAGES,
			       REQ_OP_READ | REQ_META, eb->fs_info,
@@ -4312,7 +4311,7 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
		 * won't disappear out from under us.
		 */
		spin_lock(&eb->refs_lock);
		if (atomic_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
		if (refcount_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
			spin_unlock(&eb->refs_lock);
			continue;
		}
@@ -4378,7 +4377,7 @@ int try_release_extent_buffer(struct folio *folio)
	 * this page.
	 */
	spin_lock(&eb->refs_lock);
	if (atomic_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
	if (refcount_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
		spin_unlock(&eb->refs_lock);
		spin_unlock(&folio->mapping->i_private_lock);
		return 0;
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ struct extent_buffer {
	void *addr;

	spinlock_t refs_lock;
	atomic_t refs;
	refcount_t refs;
	int read_mirror;
	/* >= 0 if eb belongs to a log tree, -1 otherwise */
	s8 log_index;
+1 −1
Original line number Diff line number Diff line
@@ -320,7 +320,7 @@ static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *p
	 * the cost of allocating a new one.
	 */
	ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED, &clone->bflags));
	atomic_inc(&clone->refs);
	refcount_inc(&clone->refs);

	ret = btrfs_next_leaf(inode->root, path);
	if (ret != 0)
Loading