Skip to content

Commit

Permalink
Btrfs: use a cached state for extent state operations during delalloc
Browse files Browse the repository at this point in the history
This changes the btrfs code to find delalloc ranges in the extent state
tree to use the new state caching code from set/test bit.  It reduces
one of the biggest causes of rbtree searches in the writeback path.

test_range_bit is also modified to take the cached state as a starting
point while searching.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 11, 2009
1 parent d5550c6 commit 9655d29
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 24 deletions.
46 changes: 31 additions & 15 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,13 @@ static int set_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->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 @@ -1286,6 +1293,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
u64 delalloc_start;
u64 delalloc_end;
u64 found;
struct extent_state *cached_state = NULL;
int ret;
int loops = 0;

Expand Down Expand Up @@ -1323,6 +1331,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
/* some of the pages are gone, lets avoid looping by
* shortening the size of the delalloc range we're searching
*/
free_extent_state(cached_state);
if (!loops) {
unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
max_bytes = PAGE_CACHE_SIZE - offset;
Expand All @@ -1336,18 +1345,21 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
BUG_ON(ret);

/* step three, lock the state bits for the whole range */
lock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
lock_extent_bits(tree, delalloc_start, delalloc_end,
0, &cached_state, GFP_NOFS);

/* then test to make sure it is all still delalloc */
ret = test_range_bit(tree, delalloc_start, delalloc_end,
EXTENT_DELALLOC, 1);
EXTENT_DELALLOC, 1, cached_state);
if (!ret) {
unlock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
unlock_extent_cached(tree, delalloc_start, delalloc_end,
&cached_state, GFP_NOFS);
__unlock_for_delalloc(inode, locked_page,
delalloc_start, delalloc_end);
cond_resched();
goto again;
}
free_extent_state(cached_state);
*start = delalloc_start;
*end = delalloc_end;
out_failed:
Expand Down Expand Up @@ -1530,14 +1542,17 @@ int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
* range is found set.
*/
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
int bits, int filled)
int bits, int filled, struct extent_state *cached)
{
struct extent_state *state = NULL;
struct rb_node *node;
int bitset = 0;

spin_lock(&tree->lock);
node = tree_search(tree, start);
if (cached && cached->tree && cached->start == start)
node = &cached->rb_node;
else
node = tree_search(tree, start);
while (node && start <= end) {
state = rb_entry(node, struct extent_state, rb_node);

Expand Down Expand Up @@ -1580,7 +1595,7 @@ static int check_page_uptodate(struct extent_io_tree *tree,
{
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
u64 end = start + PAGE_CACHE_SIZE - 1;
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1))
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL))
SetPageUptodate(page);
return 0;
}
Expand All @@ -1594,7 +1609,7 @@ static int check_page_locked(struct extent_io_tree *tree,
{
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
u64 end = start + PAGE_CACHE_SIZE - 1;
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0))
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0, NULL))
unlock_page(page);
return 0;
}
Expand Down Expand Up @@ -2032,7 +2047,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
continue;
}
/* the get_extent function already copied into the page */
if (test_range_bit(tree, cur, cur_end, EXTENT_UPTODATE, 1)) {
if (test_range_bit(tree, cur, cur_end,
EXTENT_UPTODATE, 1, NULL)) {
check_page_uptodate(tree, page);
unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
cur = cur + iosize;
Expand Down Expand Up @@ -2305,7 +2321,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
}
/* leave this out until we have a page_mkwrite call */
if (0 && !test_range_bit(tree, cur, cur + iosize - 1,
EXTENT_DIRTY, 0)) {
EXTENT_DIRTY, 0, NULL)) {
cur = cur + iosize;
pg_offset += iosize;
continue;
Expand Down Expand Up @@ -2721,7 +2737,7 @@ int extent_prepare_write(struct extent_io_tree *tree,
!isnew && !PageUptodate(page) &&
(block_off_end > to || block_off_start < from) &&
!test_range_bit(tree, block_start, cur_end,
EXTENT_UPTODATE, 1)) {
EXTENT_UPTODATE, 1, NULL)) {
u64 sector;
u64 extent_offset = block_start - em->start;
size_t iosize;
Expand Down Expand Up @@ -2776,7 +2792,7 @@ int try_release_extent_state(struct extent_map_tree *map,
int ret = 1;

if (test_range_bit(tree, start, end,
EXTENT_IOBITS | EXTENT_ORDERED, 0))
EXTENT_IOBITS | EXTENT_ORDERED, 0, NULL))
ret = 0;
else {
if ((mask & GFP_NOFS) == GFP_NOFS)
Expand Down Expand Up @@ -2821,7 +2837,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
extent_map_end(em) - 1,
EXTENT_LOCKED | EXTENT_WRITEBACK |
EXTENT_ORDERED,
0)) {
0, NULL)) {
remove_extent_mapping(map, em);
/* once for the rb tree */
free_extent_map(em);
Expand Down Expand Up @@ -3237,7 +3253,7 @@ int extent_range_uptodate(struct extent_io_tree *tree,
int uptodate;
unsigned long index;

ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1);
ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL);
if (ret)
return 1;
while (start <= end) {
Expand Down Expand Up @@ -3267,7 +3283,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
return 1;

ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
EXTENT_UPTODATE, 1);
EXTENT_UPTODATE, 1, NULL);
if (ret)
return ret;

Expand Down Expand Up @@ -3303,7 +3319,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
return 0;

if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
EXTENT_UPTODATE, 1)) {
EXTENT_UPTODATE, 1, NULL)) {
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/extent_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ u64 count_range_bits(struct extent_io_tree *tree,
u64 max_bytes, unsigned long bits);

int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
int bits, int filled);
int bits, int filled, struct extent_state *cached_state);
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
int bits, gfp_t mask);
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
Expand Down
6 changes: 3 additions & 3 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)

/* already ordered? We're done */
if (test_range_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
EXTENT_ORDERED, 0)) {
EXTENT_ORDERED, 0, NULL)) {
goto out;
}

Expand Down Expand Up @@ -1417,7 +1417,7 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
int ret;

ret = test_range_bit(&BTRFS_I(inode)->io_tree, start, end,
EXTENT_ORDERED, 0);
EXTENT_ORDERED, 0, NULL);
if (ret)
return 0;

Expand Down Expand Up @@ -1795,7 +1795,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
return 0;

if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1)) {
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) {
clear_extent_bits(io_tree, start, end, EXTENT_NODATASUM,
GFP_NOFS);
return 0;
Expand Down
8 changes: 4 additions & 4 deletions fs/btrfs/ordered-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,

ret = test_range_bit(io_tree, entry->file_offset,
entry->file_offset + entry->len - 1,
EXTENT_ORDERED, 0);
EXTENT_ORDERED, 0, NULL);
if (ret == 0)
ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
out:
Expand Down Expand Up @@ -522,7 +522,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
end--;
}
if (test_range_bit(&BTRFS_I(inode)->io_tree, start, orig_end,
EXTENT_ORDERED | EXTENT_DELALLOC, 0)) {
EXTENT_ORDERED | EXTENT_DELALLOC, 0, NULL)) {
schedule_timeout(1);
goto again;
}
Expand Down Expand Up @@ -613,7 +613,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
*/
if (test_range_bit(io_tree, disk_i_size,
ordered->file_offset + ordered->len - 1,
EXTENT_DELALLOC, 0)) {
EXTENT_DELALLOC, 0, NULL)) {
goto out;
}
/*
Expand Down Expand Up @@ -664,7 +664,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
*/
if (i_size_test > entry_end(ordered) &&
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
EXTENT_DELALLOC, 0)) {
EXTENT_DELALLOC, 0, NULL)) {
new_i_size = min_t(u64, i_size_test, i_size_read(inode));
}
BTRFS_I(inode)->disk_i_size = new_i_size;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -2180,7 +2180,7 @@ static int tree_block_processed(u64 bytenr, u32 blocksize,
struct reloc_control *rc)
{
if (test_range_bit(&rc->processed_blocks, bytenr,
bytenr + blocksize - 1, EXTENT_DIRTY, 1))
bytenr + blocksize - 1, EXTENT_DIRTY, 1, NULL))
return 1;
return 0;
}
Expand Down

0 comments on commit 9655d29

Please sign in to comment.