diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-09-02 15:22:30 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-09-11 13:31:07 -0400 |
commit | 9655d2982b53fdb38a9e0f2f11315b99b92d66e2 (patch) | |
tree | e1271f2f2a3c2c356e0692b36a2d4742b5d651d8 /fs/btrfs/extent_io.c | |
parent | d5550c6315fe0647b7ac21a6a736bf4a42620eac (diff) |
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 <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 04fafc3cffc0..c9a438d374b6 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -720,6 +720,13 @@ again: | |||
720 | } | 720 | } |
721 | 721 | ||
722 | spin_lock(&tree->lock); | 722 | 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 | } | ||
723 | /* | 730 | /* |
724 | * this search will find all the extents that end after | 731 | * this search will find all the extents that end after |
725 | * our range starts. | 732 | * our range starts. |
@@ -1286,6 +1293,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode, | |||
1286 | u64 delalloc_start; | 1293 | u64 delalloc_start; |
1287 | u64 delalloc_end; | 1294 | u64 delalloc_end; |
1288 | u64 found; | 1295 | u64 found; |
1296 | struct extent_state *cached_state = NULL; | ||
1289 | int ret; | 1297 | int ret; |
1290 | int loops = 0; | 1298 | int loops = 0; |
1291 | 1299 | ||
@@ -1323,6 +1331,7 @@ again: | |||
1323 | /* some of the pages are gone, lets avoid looping by | 1331 | /* some of the pages are gone, lets avoid looping by |
1324 | * shortening the size of the delalloc range we're searching | 1332 | * shortening the size of the delalloc range we're searching |
1325 | */ | 1333 | */ |
1334 | free_extent_state(cached_state); | ||
1326 | if (!loops) { | 1335 | if (!loops) { |
1327 | unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1); | 1336 | unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1); |
1328 | max_bytes = PAGE_CACHE_SIZE - offset; | 1337 | max_bytes = PAGE_CACHE_SIZE - offset; |
@@ -1336,18 +1345,21 @@ again: | |||
1336 | BUG_ON(ret); | 1345 | BUG_ON(ret); |
1337 | 1346 | ||
1338 | /* step three, lock the state bits for the whole range */ | 1347 | /* 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); | ||
1340 | 1350 | ||
1341 | /* then test to make sure it is all still delalloc */ | 1351 | /* then test to make sure it is all still delalloc */ |
1342 | ret = test_range_bit(tree, delalloc_start, delalloc_end, | 1352 | ret = test_range_bit(tree, delalloc_start, delalloc_end, |
1343 | EXTENT_DELALLOC, 1); | 1353 | EXTENT_DELALLOC, 1, cached_state); |
1344 | if (!ret) { | 1354 | 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); | ||
1346 | __unlock_for_delalloc(inode, locked_page, | 1357 | __unlock_for_delalloc(inode, locked_page, |
1347 | delalloc_start, delalloc_end); | 1358 | delalloc_start, delalloc_end); |
1348 | cond_resched(); | 1359 | cond_resched(); |
1349 | goto again; | 1360 | goto again; |
1350 | } | 1361 | } |
1362 | free_extent_state(cached_state); | ||
1351 | *start = delalloc_start; | 1363 | *start = delalloc_start; |
1352 | *end = delalloc_end; | 1364 | *end = delalloc_end; |
1353 | out_failed: | 1365 | out_failed: |
@@ -1530,14 +1542,17 @@ out: | |||
1530 | * range is found set. | 1542 | * range is found set. |
1531 | */ | 1543 | */ |
1532 | int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, | 1544 | 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) |
1534 | { | 1546 | { |
1535 | struct extent_state *state = NULL; | 1547 | struct extent_state *state = NULL; |
1536 | struct rb_node *node; | 1548 | struct rb_node *node; |
1537 | int bitset = 0; | 1549 | int bitset = 0; |
1538 | 1550 | ||
1539 | spin_lock(&tree->lock); | 1551 | 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); | ||
1541 | while (node && start <= end) { | 1556 | while (node && start <= end) { |
1542 | state = rb_entry(node, struct extent_state, rb_node); | 1557 | state = rb_entry(node, struct extent_state, rb_node); |
1543 | 1558 | ||
@@ -1580,7 +1595,7 @@ static int check_page_uptodate(struct extent_io_tree *tree, | |||
1580 | { | 1595 | { |
1581 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 1596 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
1582 | u64 end = start + PAGE_CACHE_SIZE - 1; | 1597 | 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)) |
1584 | SetPageUptodate(page); | 1599 | SetPageUptodate(page); |
1585 | return 0; | 1600 | return 0; |
1586 | } | 1601 | } |
@@ -1594,7 +1609,7 @@ static int check_page_locked(struct extent_io_tree *tree, | |||
1594 | { | 1609 | { |
1595 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 1610 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
1596 | u64 end = start + PAGE_CACHE_SIZE - 1; | 1611 | 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)) |
1598 | unlock_page(page); | 1613 | unlock_page(page); |
1599 | return 0; | 1614 | return 0; |
1600 | } | 1615 | } |
@@ -2032,7 +2047,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | |||
2032 | continue; | 2047 | continue; |
2033 | } | 2048 | } |
2034 | /* the get_extent function already copied into the page */ | 2049 | /* 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)) { | ||
2036 | check_page_uptodate(tree, page); | 2052 | check_page_uptodate(tree, page); |
2037 | unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); | 2053 | unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); |
2038 | cur = cur + iosize; | 2054 | cur = cur + iosize; |
@@ -2305,7 +2321,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
2305 | } | 2321 | } |
2306 | /* leave this out until we have a page_mkwrite call */ | 2322 | /* leave this out until we have a page_mkwrite call */ |
2307 | if (0 && !test_range_bit(tree, cur, cur + iosize - 1, | 2323 | if (0 && !test_range_bit(tree, cur, cur + iosize - 1, |
2308 | EXTENT_DIRTY, 0)) { | 2324 | EXTENT_DIRTY, 0, NULL)) { |
2309 | cur = cur + iosize; | 2325 | cur = cur + iosize; |
2310 | pg_offset += iosize; | 2326 | pg_offset += iosize; |
2311 | continue; | 2327 | continue; |
@@ -2721,7 +2737,7 @@ int extent_prepare_write(struct extent_io_tree *tree, | |||
2721 | !isnew && !PageUptodate(page) && | 2737 | !isnew && !PageUptodate(page) && |
2722 | (block_off_end > to || block_off_start < from) && | 2738 | (block_off_end > to || block_off_start < from) && |
2723 | !test_range_bit(tree, block_start, cur_end, | 2739 | !test_range_bit(tree, block_start, cur_end, |
2724 | EXTENT_UPTODATE, 1)) { | 2740 | EXTENT_UPTODATE, 1, NULL)) { |
2725 | u64 sector; | 2741 | u64 sector; |
2726 | u64 extent_offset = block_start - em->start; | 2742 | u64 extent_offset = block_start - em->start; |
2727 | size_t iosize; | 2743 | size_t iosize; |
@@ -2776,7 +2792,7 @@ int try_release_extent_state(struct extent_map_tree *map, | |||
2776 | int ret = 1; | 2792 | int ret = 1; |
2777 | 2793 | ||
2778 | if (test_range_bit(tree, start, end, | 2794 | if (test_range_bit(tree, start, end, |
2779 | EXTENT_IOBITS | EXTENT_ORDERED, 0)) | 2795 | EXTENT_IOBITS | EXTENT_ORDERED, 0, NULL)) |
2780 | ret = 0; | 2796 | ret = 0; |
2781 | else { | 2797 | else { |
2782 | if ((mask & GFP_NOFS) == GFP_NOFS) | 2798 | if ((mask & GFP_NOFS) == GFP_NOFS) |
@@ -2821,7 +2837,7 @@ int try_release_extent_mapping(struct extent_map_tree *map, | |||
2821 | extent_map_end(em) - 1, | 2837 | extent_map_end(em) - 1, |
2822 | EXTENT_LOCKED | EXTENT_WRITEBACK | | 2838 | EXTENT_LOCKED | EXTENT_WRITEBACK | |
2823 | EXTENT_ORDERED, | 2839 | EXTENT_ORDERED, |
2824 | 0)) { | 2840 | 0, NULL)) { |
2825 | remove_extent_mapping(map, em); | 2841 | remove_extent_mapping(map, em); |
2826 | /* once for the rb tree */ | 2842 | /* once for the rb tree */ |
2827 | free_extent_map(em); | 2843 | free_extent_map(em); |
@@ -3237,7 +3253,7 @@ int extent_range_uptodate(struct extent_io_tree *tree, | |||
3237 | int uptodate; | 3253 | int uptodate; |
3238 | unsigned long index; | 3254 | unsigned long index; |
3239 | 3255 | ||
3240 | ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1); | 3256 | ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL); |
3241 | if (ret) | 3257 | if (ret) |
3242 | return 1; | 3258 | return 1; |
3243 | while (start <= end) { | 3259 | while (start <= end) { |
@@ -3267,7 +3283,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3267 | return 1; | 3283 | return 1; |
3268 | 3284 | ||
3269 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, | 3285 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, |
3270 | EXTENT_UPTODATE, 1); | 3286 | EXTENT_UPTODATE, 1, NULL); |
3271 | if (ret) | 3287 | if (ret) |
3272 | return ret; | 3288 | return ret; |
3273 | 3289 | ||
@@ -3303,7 +3319,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
3303 | return 0; | 3319 | return 0; |
3304 | 3320 | ||
3305 | if (test_range_bit(tree, eb->start, eb->start + eb->len - 1, | 3321 | if (test_range_bit(tree, eb->start, eb->start + eb->len - 1, |
3306 | EXTENT_UPTODATE, 1)) { | 3322 | EXTENT_UPTODATE, 1, NULL)) { |
3307 | return 0; | 3323 | return 0; |
3308 | } | 3324 | } |
3309 | 3325 | ||