aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2012-09-27 17:07:30 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-09 09:15:41 -0400
commite6138876ad8327250d77291b3262fee356267211 (patch)
treeffc3fe0a05e0fd7e55b92e3ef8bad42d3c73d68c /fs/btrfs
parentce1953325662fa597197ce728e4195582fc21c8d (diff)
Btrfs: cache extent state when writing out dirty metadata pages
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/extent-tree.c5
-rw-r--r--fs/btrfs/extent_io.c43
-rw-r--r--fs/btrfs/extent_io.h6
-rw-r--r--fs/btrfs/free-space-cache.c2
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/transaction.c14
-rw-r--r--fs/btrfs/tree-log.c3
8 files changed, 63 insertions, 16 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index aa02eab8c40b..c69995556f61 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3572,7 +3572,7 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root,
3572 3572
3573 while (1) { 3573 while (1) {
3574 ret = find_first_extent_bit(dirty_pages, start, &start, &end, 3574 ret = find_first_extent_bit(dirty_pages, start, &start, &end,
3575 mark); 3575 mark, NULL);
3576 if (ret) 3576 if (ret)
3577 break; 3577 break;
3578 3578
@@ -3627,7 +3627,7 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
3627again: 3627again:
3628 while (1) { 3628 while (1) {
3629 ret = find_first_extent_bit(unpin, 0, &start, &end, 3629 ret = find_first_extent_bit(unpin, 0, &start, &end,
3630 EXTENT_DIRTY); 3630 EXTENT_DIRTY, NULL);
3631 if (ret) 3631 if (ret)
3632 break; 3632 break;
3633 3633
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3270b1087850..ca4aad96f814 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -312,7 +312,8 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
312 while (start < end) { 312 while (start < end) {
313 ret = find_first_extent_bit(info->pinned_extents, start, 313 ret = find_first_extent_bit(info->pinned_extents, start,
314 &extent_start, &extent_end, 314 &extent_start, &extent_end,
315 EXTENT_DIRTY | EXTENT_UPTODATE); 315 EXTENT_DIRTY | EXTENT_UPTODATE,
316 NULL);
316 if (ret) 317 if (ret)
317 break; 318 break;
318 319
@@ -5045,7 +5046,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
5045 5046
5046 while (1) { 5047 while (1) {
5047 ret = find_first_extent_bit(unpin, 0, &start, &end, 5048 ret = find_first_extent_bit(unpin, 0, &start, &end,
5048 EXTENT_DIRTY); 5049 EXTENT_DIRTY, NULL);
5049 if (ret) 5050 if (ret)
5050 break; 5051 break;
5051 5052
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 979fa0d6bfee..e8ee39b73356 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -937,6 +937,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
937 * @end: the end offset in bytes (inclusive) 937 * @end: the end offset in bytes (inclusive)
938 * @bits: the bits to set in this range 938 * @bits: the bits to set in this range
939 * @clear_bits: the bits to clear in this range 939 * @clear_bits: the bits to clear in this range
940 * @cached_state: state that we're going to cache
940 * @mask: the allocation mask 941 * @mask: the allocation mask
941 * 942 *
942 * This will go through and set bits for the given range. If any states exist 943 * This will go through and set bits for the given range. If any states exist
@@ -946,7 +947,8 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
946 * boundary bits like LOCK. 947 * boundary bits like LOCK.
947 */ 948 */
948int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, 949int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
949 int bits, int clear_bits, gfp_t mask) 950 int bits, int clear_bits,
951 struct extent_state **cached_state, gfp_t mask)
950{ 952{
951 struct extent_state *state; 953 struct extent_state *state;
952 struct extent_state *prealloc = NULL; 954 struct extent_state *prealloc = NULL;
@@ -963,6 +965,15 @@ again:
963 } 965 }
964 966
965 spin_lock(&tree->lock); 967 spin_lock(&tree->lock);
968 if (cached_state && *cached_state) {
969 state = *cached_state;
970 if (state->start <= start && state->end > start &&
971 state->tree) {
972 node = &state->rb_node;
973 goto hit_next;
974 }
975 }
976
966 /* 977 /*
967 * this search will find all the extents that end after 978 * this search will find all the extents that end after
968 * our range starts. 979 * our range starts.
@@ -993,6 +1004,7 @@ hit_next:
993 */ 1004 */
994 if (state->start == start && state->end <= end) { 1005 if (state->start == start && state->end <= end) {
995 set_state_bits(tree, state, &bits); 1006 set_state_bits(tree, state, &bits);
1007 cache_state(state, cached_state);
996 state = clear_state_bit(tree, state, &clear_bits, 0); 1008 state = clear_state_bit(tree, state, &clear_bits, 0);
997 if (last_end == (u64)-1) 1009 if (last_end == (u64)-1)
998 goto out; 1010 goto out;
@@ -1033,6 +1045,7 @@ hit_next:
1033 goto out; 1045 goto out;
1034 if (state->end <= end) { 1046 if (state->end <= end) {
1035 set_state_bits(tree, state, &bits); 1047 set_state_bits(tree, state, &bits);
1048 cache_state(state, cached_state);
1036 state = clear_state_bit(tree, state, &clear_bits, 0); 1049 state = clear_state_bit(tree, state, &clear_bits, 0);
1037 if (last_end == (u64)-1) 1050 if (last_end == (u64)-1)
1038 goto out; 1051 goto out;
@@ -1071,6 +1084,7 @@ hit_next:
1071 &bits); 1084 &bits);
1072 if (err) 1085 if (err)
1073 extent_io_tree_panic(tree, err); 1086 extent_io_tree_panic(tree, err);
1087 cache_state(prealloc, cached_state);
1074 prealloc = NULL; 1088 prealloc = NULL;
1075 start = this_end + 1; 1089 start = this_end + 1;
1076 goto search_again; 1090 goto search_again;
@@ -1093,6 +1107,7 @@ hit_next:
1093 extent_io_tree_panic(tree, err); 1107 extent_io_tree_panic(tree, err);
1094 1108
1095 set_state_bits(tree, prealloc, &bits); 1109 set_state_bits(tree, prealloc, &bits);
1110 cache_state(prealloc, cached_state);
1096 clear_state_bit(tree, prealloc, &clear_bits, 0); 1111 clear_state_bit(tree, prealloc, &clear_bits, 0);
1097 prealloc = NULL; 1112 prealloc = NULL;
1098 goto out; 1113 goto out;
@@ -1297,18 +1312,42 @@ out:
1297 * If nothing was found, 1 is returned. If found something, return 0. 1312 * If nothing was found, 1 is returned. If found something, return 0.
1298 */ 1313 */
1299int find_first_extent_bit(struct extent_io_tree *tree, u64 start, 1314int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
1300 u64 *start_ret, u64 *end_ret, int bits) 1315 u64 *start_ret, u64 *end_ret, int bits,
1316 struct extent_state **cached_state)
1301{ 1317{
1302 struct extent_state *state; 1318 struct extent_state *state;
1319 struct rb_node *n;
1303 int ret = 1; 1320 int ret = 1;
1304 1321
1305 spin_lock(&tree->lock); 1322 spin_lock(&tree->lock);
1323 if (cached_state && *cached_state) {
1324 state = *cached_state;
1325 if (state->end == start - 1 && state->tree) {
1326 n = rb_next(&state->rb_node);
1327 while (n) {
1328 state = rb_entry(n, struct extent_state,
1329 rb_node);
1330 if (state->state & bits)
1331 goto got_it;
1332 n = rb_next(n);
1333 }
1334 free_extent_state(*cached_state);
1335 *cached_state = NULL;
1336 goto out;
1337 }
1338 free_extent_state(*cached_state);
1339 *cached_state = NULL;
1340 }
1341
1306 state = find_first_extent_bit_state(tree, start, bits); 1342 state = find_first_extent_bit_state(tree, start, bits);
1343got_it:
1307 if (state) { 1344 if (state) {
1345 cache_state(state, cached_state);
1308 *start_ret = state->start; 1346 *start_ret = state->start;
1309 *end_ret = state->end; 1347 *end_ret = state->end;
1310 ret = 0; 1348 ret = 0;
1311 } 1349 }
1350out:
1312 spin_unlock(&tree->lock); 1351 spin_unlock(&tree->lock);
1313 return ret; 1352 return ret;
1314} 1353}
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index a69dea219044..7aeb31087f88 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -233,13 +233,15 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
233int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, 233int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
234 gfp_t mask); 234 gfp_t mask);
235int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, 235int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
236 int bits, int clear_bits, gfp_t mask); 236 int bits, int clear_bits,
237 struct extent_state **cached_state, gfp_t mask);
237int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, 238int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
238 struct extent_state **cached_state, gfp_t mask); 239 struct extent_state **cached_state, gfp_t mask);
239int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end, 240int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
240 struct extent_state **cached_state, gfp_t mask); 241 struct extent_state **cached_state, gfp_t mask);
241int find_first_extent_bit(struct extent_io_tree *tree, u64 start, 242int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
242 u64 *start_ret, u64 *end_ret, int bits); 243 u64 *start_ret, u64 *end_ret, int bits,
244 struct extent_state **cached_state);
243struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree, 245struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
244 u64 start, int bits); 246 u64 start, int bits);
245int extent_invalidatepage(struct extent_io_tree *tree, 247int extent_invalidatepage(struct extent_io_tree *tree,
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index b107e68797f4..1027b854b90c 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -966,7 +966,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
966 block_group->key.offset)) { 966 block_group->key.offset)) {
967 ret = find_first_extent_bit(unpin, start, 967 ret = find_first_extent_bit(unpin, start,
968 &extent_start, &extent_end, 968 &extent_start, &extent_end,
969 EXTENT_DIRTY); 969 EXTENT_DIRTY, NULL);
970 if (ret) { 970 if (ret) {
971 ret = 0; 971 ret = 0;
972 break; 972 break;
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 6e530bb86c94..776f0aa128fc 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3621,7 +3621,7 @@ next:
3621 3621
3622 ret = find_first_extent_bit(&rc->processed_blocks, 3622 ret = find_first_extent_bit(&rc->processed_blocks,
3623 key.objectid, &start, &end, 3623 key.objectid, &start, &end,
3624 EXTENT_DIRTY); 3624 EXTENT_DIRTY, NULL);
3625 3625
3626 if (ret == 0 && start <= key.objectid) { 3626 if (ret == 0 && start <= key.objectid) {
3627 btrfs_release_path(path); 3627 btrfs_release_path(path);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 69139a356f71..77db875b5116 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -687,13 +687,15 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
687 int err = 0; 687 int err = 0;
688 int werr = 0; 688 int werr = 0;
689 struct address_space *mapping = root->fs_info->btree_inode->i_mapping; 689 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
690 struct extent_state *cached_state = NULL;
690 u64 start = 0; 691 u64 start = 0;
691 u64 end; 692 u64 end;
692 693
693 while (!find_first_extent_bit(dirty_pages, start, &start, &end, 694 while (!find_first_extent_bit(dirty_pages, start, &start, &end,
694 mark)) { 695 mark, &cached_state)) {
695 convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT, mark, 696 convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
696 GFP_NOFS); 697 mark, &cached_state, GFP_NOFS);
698 cached_state = NULL;
697 err = filemap_fdatawrite_range(mapping, start, end); 699 err = filemap_fdatawrite_range(mapping, start, end);
698 if (err) 700 if (err)
699 werr = err; 701 werr = err;
@@ -717,12 +719,14 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
717 int err = 0; 719 int err = 0;
718 int werr = 0; 720 int werr = 0;
719 struct address_space *mapping = root->fs_info->btree_inode->i_mapping; 721 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
722 struct extent_state *cached_state = NULL;
720 u64 start = 0; 723 u64 start = 0;
721 u64 end; 724 u64 end;
722 725
723 while (!find_first_extent_bit(dirty_pages, start, &start, &end, 726 while (!find_first_extent_bit(dirty_pages, start, &start, &end,
724 EXTENT_NEED_WAIT)) { 727 EXTENT_NEED_WAIT, &cached_state)) {
725 clear_extent_bits(dirty_pages, start, end, EXTENT_NEED_WAIT, GFP_NOFS); 728 clear_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
729 0, 0, &cached_state, GFP_NOFS);
726 err = filemap_fdatawait_range(mapping, start, end); 730 err = filemap_fdatawait_range(mapping, start, end);
727 if (err) 731 if (err)
728 werr = err; 732 werr = err;
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 1d7b34844323..f4b9e54b1da2 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -2463,7 +2463,8 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
2463 2463
2464 while (1) { 2464 while (1) {
2465 ret = find_first_extent_bit(&log->dirty_log_pages, 2465 ret = find_first_extent_bit(&log->dirty_log_pages,
2466 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW); 2466 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
2467 NULL);
2467 if (ret) 2468 if (ret)
2468 break; 2469 break;
2469 2470