Commit e38e2ed7 authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason
Browse files

Btrfs: make find_first_extent_bit be able to cache any state



Right now the only caller of find_first_extent_bit() that is interested
in caching extent states (transaction or log commit), never gets an extent
state cached. This is because find_first_extent_bit() only caches states
that have at least one of the flags EXTENT_IOBITS or EXTENT_BOUNDARY, and
the transaction/log commit caller always passes a tree that doesn't have
ever extent states with any of those flags (they can only have one of the
following flags: EXTENT_DIRTY, EXTENT_NEW or EXTENT_NEED_WAIT).

This change together with the following one in the patch series (titled
"Btrfs: avoid returning -ENOMEM in convert_extent_bit() too early") will
help reduce significantly the chances of calls to convert_extent_bit()
fail with -ENOMEM when called from the transaction/log commit code.

Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 663dfbb0
Loading
Loading
Loading
Loading
+12 −4
Original line number Original line Diff line number Diff line
@@ -796,17 +796,25 @@ static void set_state_bits(struct extent_io_tree *tree,
	state->state |= bits_to_set;
	state->state |= bits_to_set;
}
}


static void cache_state(struct extent_state *state,
static void cache_state_if_flags(struct extent_state *state,
			struct extent_state **cached_ptr)
				 struct extent_state **cached_ptr,
				 const u64 flags)
{
{
	if (cached_ptr && !(*cached_ptr)) {
	if (cached_ptr && !(*cached_ptr)) {
		if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) {
		if (!flags || (state->state & flags)) {
			*cached_ptr = state;
			*cached_ptr = state;
			atomic_inc(&state->refs);
			atomic_inc(&state->refs);
		}
		}
	}
	}
}
}


static void cache_state(struct extent_state *state,
			struct extent_state **cached_ptr)
{
	return cache_state_if_flags(state, cached_ptr,
				    EXTENT_IOBITS | EXTENT_BOUNDARY);
}

/*
/*
 * set some bits on a range in the tree.  This may require allocations or
 * set some bits on a range in the tree.  This may require allocations or
 * sleeping, so the gfp mask is used to indicate what is allowed.
 * sleeping, so the gfp mask is used to indicate what is allowed.
@@ -1482,7 +1490,7 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
	state = find_first_extent_bit_state(tree, start, bits);
	state = find_first_extent_bit_state(tree, start, bits);
got_it:
got_it:
	if (state) {
	if (state) {
		cache_state(state, cached_state);
		cache_state_if_flags(state, cached_state, 0);
		*start_ret = state->start;
		*start_ret = state->start;
		*end_ret = state->end;
		*end_ret = state->end;
		ret = 0;
		ret = 0;
+3 −0
Original line number Original line Diff line number Diff line
@@ -883,6 +883,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
			werr = err;
			werr = err;
		else if (wait_writeback)
		else if (wait_writeback)
			werr = filemap_fdatawait_range(mapping, start, end);
			werr = filemap_fdatawait_range(mapping, start, end);
		free_extent_state(cached_state);
		cached_state = NULL;
		cached_state = NULL;
		cond_resched();
		cond_resched();
		start = end + 1;
		start = end + 1;
@@ -927,6 +928,8 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
			err = filemap_fdatawait_range(mapping, start, end);
			err = filemap_fdatawait_range(mapping, start, end);
		if (err)
		if (err)
			werr = err;
			werr = err;
		free_extent_state(cached_state);
		cached_state = NULL;
		cond_resched();
		cond_resched();
		start = end + 1;
		start = end + 1;
	}
	}