Btrfs: make find_first_extent_bit be able to cache any state
authorFilipe Manana <fdmanana@suse.com>
Mon, 13 Oct 2014 11:28:38 +0000 (12:28 +0100)
committerChris Mason <clm@fb.com>
Fri, 21 Nov 2014 01:14:29 +0000 (17:14 -0800)
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: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/extent_io.c
fs/btrfs/transaction.c

index 420fe26d32d56b60f57454f9daa8356b9318ed50..0d931b143c00faa889eb26f362fa5b37b28bc231 100644 (file)
@@ -796,17 +796,25 @@ static void set_state_bits(struct extent_io_tree *tree,
        state->state |= bits_to_set;
 }
 
-static void cache_state(struct extent_state *state,
-                       struct extent_state **cached_ptr)
+static void cache_state_if_flags(struct extent_state *state,
+                                struct extent_state **cached_ptr,
+                                const u64 flags)
 {
        if (cached_ptr && !(*cached_ptr)) {
-               if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) {
+               if (!flags || (state->state & flags)) {
                        *cached_ptr = state;
                        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
  * 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);
 got_it:
        if (state) {
-               cache_state(state, cached_state);
+               cache_state_if_flags(state, cached_state, 0);
                *start_ret = state->start;
                *end_ret = state->end;
                ret = 0;
index 04dbc800c209128e5d0188c661a2a25140cb8b0b..16c704b68704c7dcc979b2e1f52c502ea4ab6c1a 100644 (file)
@@ -883,6 +883,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
                        werr = err;
                else if (wait_writeback)
                        werr = filemap_fdatawait_range(mapping, start, end);
+               free_extent_state(cached_state);
                cached_state = NULL;
                cond_resched();
                start = end + 1;
@@ -927,6 +928,8 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
                        err = filemap_fdatawait_range(mapping, start, end);
                if (err)
                        werr = err;
+               free_extent_state(cached_state);
+               cached_state = NULL;
                cond_resched();
                start = end + 1;
        }