Skip to content

Commit

Permalink
Btrfs: cache extent state when writing out dirty metadata pages
Browse files Browse the repository at this point in the history
Everytime we write out dirty pages we search for an offset in the tree,
convert the bits in the state, and then when we wait we search for the
offset again and clear the bits.  So for every dirty range in the io tree we
are doing 4 rb searches, which is suboptimal.  With this patch we are only
doing 2 searches for every cycle (modulo weird things happening).  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
  • Loading branch information
Josef Bacik authored and Chris Mason committed Oct 9, 2012
1 parent ce19533 commit e613887
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 16 deletions.
4 changes: 2 additions & 2 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3572,7 +3572,7 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root,

while (1) {
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
mark);
mark, NULL);
if (ret)
break;

Expand Down Expand Up @@ -3627,7 +3627,7 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
again:
while (1) {
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY);
EXTENT_DIRTY, NULL);
if (ret)
break;

Expand Down
5 changes: 3 additions & 2 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
while (start < end) {
ret = find_first_extent_bit(info->pinned_extents, start,
&extent_start, &extent_end,
EXTENT_DIRTY | EXTENT_UPTODATE);
EXTENT_DIRTY | EXTENT_UPTODATE,
NULL);
if (ret)
break;

Expand Down Expand Up @@ -5045,7 +5046,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,

while (1) {
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY);
EXTENT_DIRTY, NULL);
if (ret)
break;

Expand Down
43 changes: 41 additions & 2 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
* @end: the end offset in bytes (inclusive)
* @bits: the bits to set in this range
* @clear_bits: the bits to clear in this range
* @cached_state: state that we're going to cache
* @mask: the allocation mask
*
* This will go through and set bits for the given range. If any states exist
Expand All @@ -946,7 +947,8 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
* boundary bits like LOCK.
*/
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
int bits, int clear_bits, gfp_t mask)
int bits, int clear_bits,
struct extent_state **cached_state, gfp_t mask)
{
struct extent_state *state;
struct extent_state *prealloc = NULL;
Expand All @@ -963,6 +965,15 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
}

spin_lock(&tree->lock);
if (cached_state && *cached_state) {
state = *cached_state;
if (state->start <= start && state->end > start &&
state->tree) {
node = &state->rb_node;
goto hit_next;
}
}

/*
* this search will find all the extents that end after
* our range starts.
Expand Down Expand Up @@ -993,6 +1004,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
*/
if (state->start == start && state->end <= end) {
set_state_bits(tree, state, &bits);
cache_state(state, cached_state);
state = clear_state_bit(tree, state, &clear_bits, 0);
if (last_end == (u64)-1)
goto out;
Expand Down Expand Up @@ -1033,6 +1045,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
goto out;
if (state->end <= end) {
set_state_bits(tree, state, &bits);
cache_state(state, cached_state);
state = clear_state_bit(tree, state, &clear_bits, 0);
if (last_end == (u64)-1)
goto out;
Expand Down Expand Up @@ -1071,6 +1084,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
&bits);
if (err)
extent_io_tree_panic(tree, err);
cache_state(prealloc, cached_state);
prealloc = NULL;
start = this_end + 1;
goto search_again;
Expand All @@ -1093,6 +1107,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
extent_io_tree_panic(tree, err);

set_state_bits(tree, prealloc, &bits);
cache_state(prealloc, cached_state);
clear_state_bit(tree, prealloc, &clear_bits, 0);
prealloc = NULL;
goto out;
Expand Down Expand Up @@ -1297,18 +1312,42 @@ struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
* If nothing was found, 1 is returned. If found something, return 0.
*/
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, int bits)
u64 *start_ret, u64 *end_ret, int bits,
struct extent_state **cached_state)
{
struct extent_state *state;
struct rb_node *n;
int ret = 1;

spin_lock(&tree->lock);
if (cached_state && *cached_state) {
state = *cached_state;
if (state->end == start - 1 && state->tree) {
n = rb_next(&state->rb_node);
while (n) {
state = rb_entry(n, struct extent_state,
rb_node);
if (state->state & bits)
goto got_it;
n = rb_next(n);
}
free_extent_state(*cached_state);
*cached_state = NULL;
goto out;
}
free_extent_state(*cached_state);
*cached_state = NULL;
}

state = find_first_extent_bit_state(tree, start, bits);
got_it:
if (state) {
cache_state(state, cached_state);
*start_ret = state->start;
*end_ret = state->end;
ret = 0;
}
out:
spin_unlock(&tree->lock);
return ret;
}
Expand Down
6 changes: 4 additions & 2 deletions fs/btrfs/extent_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,15 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask);
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
int bits, int clear_bits, gfp_t mask);
int bits, int clear_bits,
struct extent_state **cached_state, gfp_t mask);
int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached_state, gfp_t mask);
int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached_state, gfp_t mask);
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, int bits);
u64 *start_ret, u64 *end_ret, int bits,
struct extent_state **cached_state);
struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
u64 start, int bits);
int extent_invalidatepage(struct extent_io_tree *tree,
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/free-space-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
block_group->key.offset)) {
ret = find_first_extent_bit(unpin, start,
&extent_start, &extent_end,
EXTENT_DIRTY);
EXTENT_DIRTY, NULL);
if (ret) {
ret = 0;
break;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -3621,7 +3621,7 @@ int find_next_extent(struct btrfs_trans_handle *trans,

ret = find_first_extent_bit(&rc->processed_blocks,
key.objectid, &start, &end,
EXTENT_DIRTY);
EXTENT_DIRTY, NULL);

if (ret == 0 && start <= key.objectid) {
btrfs_release_path(path);
Expand Down
14 changes: 9 additions & 5 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,13 +687,15 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
int err = 0;
int werr = 0;
struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
struct extent_state *cached_state = NULL;
u64 start = 0;
u64 end;

while (!find_first_extent_bit(dirty_pages, start, &start, &end,
mark)) {
convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT, mark,
GFP_NOFS);
mark, &cached_state)) {
convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
mark, &cached_state, GFP_NOFS);
cached_state = NULL;
err = filemap_fdatawrite_range(mapping, start, end);
if (err)
werr = err;
Expand All @@ -717,12 +719,14 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
int err = 0;
int werr = 0;
struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
struct extent_state *cached_state = NULL;
u64 start = 0;
u64 end;

while (!find_first_extent_bit(dirty_pages, start, &start, &end,
EXTENT_NEED_WAIT)) {
clear_extent_bits(dirty_pages, start, end, EXTENT_NEED_WAIT, GFP_NOFS);
EXTENT_NEED_WAIT, &cached_state)) {
clear_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
0, 0, &cached_state, GFP_NOFS);
err = filemap_fdatawait_range(mapping, start, end);
if (err)
werr = err;
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -2463,7 +2463,8 @@ static void free_log_tree(struct btrfs_trans_handle *trans,

while (1) {
ret = find_first_extent_bit(&log->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
NULL);
if (ret)
break;

Expand Down

0 comments on commit e613887

Please sign in to comment.