Skip to content

Commit 9655d29

Browse files
committed
Btrfs: use a cached state for extent state operations during delalloc
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 <[email protected]>
1 parent d5550c6 commit 9655d29

File tree

5 files changed

+40
-24
lines changed

5 files changed

+40
-24
lines changed

fs/btrfs/extent_io.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,13 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
720720
}
721721

722722
spin_lock(&tree->lock);
723+
if (cached_state && *cached_state) {
724+
state = *cached_state;
725+
if (state->start == start && state->tree) {
726+
node = &state->rb_node;
727+
goto hit_next;
728+
}
729+
}
723730
/*
724731
* this search will find all the extents that end after
725732
* our range starts.
@@ -1286,6 +1293,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
12861293
u64 delalloc_start;
12871294
u64 delalloc_end;
12881295
u64 found;
1296+
struct extent_state *cached_state = NULL;
12891297
int ret;
12901298
int loops = 0;
12911299

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

13381347
/* step three, lock the state bits for the whole range */
1339-
lock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
1348+
lock_extent_bits(tree, delalloc_start, delalloc_end,
1349+
0, &cached_state, GFP_NOFS);
13401350

13411351
/* then test to make sure it is all still delalloc */
13421352
ret = test_range_bit(tree, delalloc_start, delalloc_end,
1343-
EXTENT_DELALLOC, 1);
1353+
EXTENT_DELALLOC, 1, cached_state);
13441354
if (!ret) {
1345-
unlock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
1355+
unlock_extent_cached(tree, delalloc_start, delalloc_end,
1356+
&cached_state, GFP_NOFS);
13461357
__unlock_for_delalloc(inode, locked_page,
13471358
delalloc_start, delalloc_end);
13481359
cond_resched();
13491360
goto again;
13501361
}
1362+
free_extent_state(cached_state);
13511363
*start = delalloc_start;
13521364
*end = delalloc_end;
13531365
out_failed:
@@ -1530,14 +1542,17 @@ int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
15301542
* range is found set.
15311543
*/
15321544
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
1533-
int bits, int filled)
1545+
int bits, int filled, struct extent_state *cached)
15341546
{
15351547
struct extent_state *state = NULL;
15361548
struct rb_node *node;
15371549
int bitset = 0;
15381550

15391551
spin_lock(&tree->lock);
1540-
node = tree_search(tree, start);
1552+
if (cached && cached->tree && cached->start == start)
1553+
node = &cached->rb_node;
1554+
else
1555+
node = tree_search(tree, start);
15411556
while (node && start <= end) {
15421557
state = rb_entry(node, struct extent_state, rb_node);
15431558

@@ -1580,7 +1595,7 @@ static int check_page_uptodate(struct extent_io_tree *tree,
15801595
{
15811596
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
15821597
u64 end = start + PAGE_CACHE_SIZE - 1;
1583-
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1))
1598+
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL))
15841599
SetPageUptodate(page);
15851600
return 0;
15861601
}
@@ -1594,7 +1609,7 @@ static int check_page_locked(struct extent_io_tree *tree,
15941609
{
15951610
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
15961611
u64 end = start + PAGE_CACHE_SIZE - 1;
1597-
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0))
1612+
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0, NULL))
15981613
unlock_page(page);
15991614
return 0;
16001615
}
@@ -2032,7 +2047,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
20322047
continue;
20332048
}
20342049
/* the get_extent function already copied into the page */
2035-
if (test_range_bit(tree, cur, cur_end, EXTENT_UPTODATE, 1)) {
2050+
if (test_range_bit(tree, cur, cur_end,
2051+
EXTENT_UPTODATE, 1, NULL)) {
20362052
check_page_uptodate(tree, page);
20372053
unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
20382054
cur = cur + iosize;
@@ -2305,7 +2321,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
23052321
}
23062322
/* leave this out until we have a page_mkwrite call */
23072323
if (0 && !test_range_bit(tree, cur, cur + iosize - 1,
2308-
EXTENT_DIRTY, 0)) {
2324+
EXTENT_DIRTY, 0, NULL)) {
23092325
cur = cur + iosize;
23102326
pg_offset += iosize;
23112327
continue;
@@ -2721,7 +2737,7 @@ int extent_prepare_write(struct extent_io_tree *tree,
27212737
!isnew && !PageUptodate(page) &&
27222738
(block_off_end > to || block_off_start < from) &&
27232739
!test_range_bit(tree, block_start, cur_end,
2724-
EXTENT_UPTODATE, 1)) {
2740+
EXTENT_UPTODATE, 1, NULL)) {
27252741
u64 sector;
27262742
u64 extent_offset = block_start - em->start;
27272743
size_t iosize;
@@ -2776,7 +2792,7 @@ int try_release_extent_state(struct extent_map_tree *map,
27762792
int ret = 1;
27772793

27782794
if (test_range_bit(tree, start, end,
2779-
EXTENT_IOBITS | EXTENT_ORDERED, 0))
2795+
EXTENT_IOBITS | EXTENT_ORDERED, 0, NULL))
27802796
ret = 0;
27812797
else {
27822798
if ((mask & GFP_NOFS) == GFP_NOFS)
@@ -2821,7 +2837,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
28212837
extent_map_end(em) - 1,
28222838
EXTENT_LOCKED | EXTENT_WRITEBACK |
28232839
EXTENT_ORDERED,
2824-
0)) {
2840+
0, NULL)) {
28252841
remove_extent_mapping(map, em);
28262842
/* once for the rb tree */
28272843
free_extent_map(em);
@@ -3237,7 +3253,7 @@ int extent_range_uptodate(struct extent_io_tree *tree,
32373253
int uptodate;
32383254
unsigned long index;
32393255

3240-
ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1);
3256+
ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL);
32413257
if (ret)
32423258
return 1;
32433259
while (start <= end) {
@@ -3267,7 +3283,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
32673283
return 1;
32683284

32693285
ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
3270-
EXTENT_UPTODATE, 1);
3286+
EXTENT_UPTODATE, 1, NULL);
32713287
if (ret)
32723288
return ret;
32733289

@@ -3303,7 +3319,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
33033319
return 0;
33043320

33053321
if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
3306-
EXTENT_UPTODATE, 1)) {
3322+
EXTENT_UPTODATE, 1, NULL)) {
33073323
return 0;
33083324
}
33093325

fs/btrfs/extent_io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ u64 count_range_bits(struct extent_io_tree *tree,
157157
u64 max_bytes, unsigned long bits);
158158

159159
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
160-
int bits, int filled);
160+
int bits, int filled, struct extent_state *cached_state);
161161
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
162162
int bits, gfp_t mask);
163163
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,

fs/btrfs/inode.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
13761376

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

@@ -1417,7 +1417,7 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
14171417
int ret;
14181418

14191419
ret = test_range_bit(&BTRFS_I(inode)->io_tree, start, end,
1420-
EXTENT_ORDERED, 0);
1420+
EXTENT_ORDERED, 0, NULL);
14211421
if (ret)
14221422
return 0;
14231423

@@ -1795,7 +1795,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
17951795
return 0;
17961796

17971797
if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
1798-
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1)) {
1798+
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) {
17991799
clear_extent_bits(io_tree, start, end, EXTENT_NODATASUM,
18001800
GFP_NOFS);
18011801
return 0;

fs/btrfs/ordered-data.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
262262

263263
ret = test_range_bit(io_tree, entry->file_offset,
264264
entry->file_offset + entry->len - 1,
265-
EXTENT_ORDERED, 0);
265+
EXTENT_ORDERED, 0, NULL);
266266
if (ret == 0)
267267
ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
268268
out:
@@ -522,7 +522,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
522522
end--;
523523
}
524524
if (test_range_bit(&BTRFS_I(inode)->io_tree, start, orig_end,
525-
EXTENT_ORDERED | EXTENT_DELALLOC, 0)) {
525+
EXTENT_ORDERED | EXTENT_DELALLOC, 0, NULL)) {
526526
schedule_timeout(1);
527527
goto again;
528528
}
@@ -613,7 +613,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
613613
*/
614614
if (test_range_bit(io_tree, disk_i_size,
615615
ordered->file_offset + ordered->len - 1,
616-
EXTENT_DELALLOC, 0)) {
616+
EXTENT_DELALLOC, 0, NULL)) {
617617
goto out;
618618
}
619619
/*
@@ -664,7 +664,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
664664
*/
665665
if (i_size_test > entry_end(ordered) &&
666666
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
667-
EXTENT_DELALLOC, 0)) {
667+
EXTENT_DELALLOC, 0, NULL)) {
668668
new_i_size = min_t(u64, i_size_test, i_size_read(inode));
669669
}
670670
BTRFS_I(inode)->disk_i_size = new_i_size;

fs/btrfs/relocation.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,7 @@ static int tree_block_processed(u64 bytenr, u32 blocksize,
21802180
struct reloc_control *rc)
21812181
{
21822182
if (test_range_bit(&rc->processed_blocks, bytenr,
2183-
bytenr + blocksize - 1, EXTENT_DIRTY, 1))
2183+
bytenr + blocksize - 1, EXTENT_DIRTY, 1, NULL))
21842184
return 1;
21852185
return 0;
21862186
}

0 commit comments

Comments
 (0)