Commit e6138876ad8327250d77291b3262fee356267211

Authored by Josef Bacik
Committed by Chris Mason
1 parent ce19533256

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>

Showing 8 changed files with 63 additions and 16 deletions Side-by-side Diff

... ... @@ -3572,7 +3572,7 @@
3572 3572  
3573 3573 while (1) {
3574 3574 ret = find_first_extent_bit(dirty_pages, start, &start, &end,
3575   - mark);
  3575 + mark, NULL);
3576 3576 if (ret)
3577 3577 break;
3578 3578  
... ... @@ -3627,7 +3627,7 @@
3627 3627 again:
3628 3628 while (1) {
3629 3629 ret = find_first_extent_bit(unpin, 0, &start, &end,
3630   - EXTENT_DIRTY);
  3630 + EXTENT_DIRTY, NULL);
3631 3631 if (ret)
3632 3632 break;
3633 3633  
fs/btrfs/extent-tree.c
... ... @@ -312,7 +312,8 @@
312 312 while (start < end) {
313 313 ret = find_first_extent_bit(info->pinned_extents, start,
314 314 &extent_start, &extent_end,
315   - EXTENT_DIRTY | EXTENT_UPTODATE);
  315 + EXTENT_DIRTY | EXTENT_UPTODATE,
  316 + NULL);
316 317 if (ret)
317 318 break;
318 319  
... ... @@ -5045,7 +5046,7 @@
5045 5046  
5046 5047 while (1) {
5047 5048 ret = find_first_extent_bit(unpin, 0, &start, &end,
5048   - EXTENT_DIRTY);
  5049 + EXTENT_DIRTY, NULL);
5049 5050 if (ret)
5050 5051 break;
5051 5052  
fs/btrfs/extent_io.c
... ... @@ -937,6 +937,7 @@
937 937 * @end: the end offset in bytes (inclusive)
938 938 * @bits: the bits to set in this range
939 939 * @clear_bits: the bits to clear in this range
  940 + * @cached_state: state that we're going to cache
940 941 * @mask: the allocation mask
941 942 *
942 943 * This will go through and set bits for the given range. If any states exist
... ... @@ -946,7 +947,8 @@
946 947 * boundary bits like LOCK.
947 948 */
948 949 int 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 953 struct extent_state *state;
952 954 struct extent_state *prealloc = NULL;
... ... @@ -963,6 +965,15 @@
963 965 }
964 966  
965 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 978 * this search will find all the extents that end after
968 979 * our range starts.
... ... @@ -993,6 +1004,7 @@
993 1004 */
994 1005 if (state->start == start && state->end <= end) {
995 1006 set_state_bits(tree, state, &bits);
  1007 + cache_state(state, cached_state);
996 1008 state = clear_state_bit(tree, state, &clear_bits, 0);
997 1009 if (last_end == (u64)-1)
998 1010 goto out;
... ... @@ -1033,6 +1045,7 @@
1033 1045 goto out;
1034 1046 if (state->end <= end) {
1035 1047 set_state_bits(tree, state, &bits);
  1048 + cache_state(state, cached_state);
1036 1049 state = clear_state_bit(tree, state, &clear_bits, 0);
1037 1050 if (last_end == (u64)-1)
1038 1051 goto out;
... ... @@ -1071,6 +1084,7 @@
1071 1084 &bits);
1072 1085 if (err)
1073 1086 extent_io_tree_panic(tree, err);
  1087 + cache_state(prealloc, cached_state);
1074 1088 prealloc = NULL;
1075 1089 start = this_end + 1;
1076 1090 goto search_again;
... ... @@ -1093,6 +1107,7 @@
1093 1107 extent_io_tree_panic(tree, err);
1094 1108  
1095 1109 set_state_bits(tree, prealloc, &bits);
  1110 + cache_state(prealloc, cached_state);
1096 1111 clear_state_bit(tree, prealloc, &clear_bits, 0);
1097 1112 prealloc = NULL;
1098 1113 goto out;
1099 1114  
1100 1115  
1101 1116  
1102 1117  
1103 1118  
... ... @@ -1297,18 +1312,42 @@
1297 1312 * If nothing was found, 1 is returned. If found something, return 0.
1298 1313 */
1299 1314 int 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 1318 struct extent_state *state;
  1319 + struct rb_node *n;
1303 1320 int ret = 1;
1304 1321  
1305 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 1342 state = find_first_extent_bit_state(tree, start, bits);
  1343 +got_it:
1307 1344 if (state) {
  1345 + cache_state(state, cached_state);
1308 1346 *start_ret = state->start;
1309 1347 *end_ret = state->end;
1310 1348 ret = 0;
1311 1349 }
  1350 +out:
1312 1351 spin_unlock(&tree->lock);
1313 1352 return ret;
1314 1353 }
fs/btrfs/extent_io.h
... ... @@ -233,13 +233,15 @@
233 233 int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
234 234 gfp_t mask);
235 235 int 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);
237 238 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
238 239 struct extent_state **cached_state, gfp_t mask);
239 240 int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
240 241 struct extent_state **cached_state, gfp_t mask);
241 242 int 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);
243 245 struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
244 246 u64 start, int bits);
245 247 int extent_invalidatepage(struct extent_io_tree *tree,
fs/btrfs/free-space-cache.c
... ... @@ -966,7 +966,7 @@
966 966 block_group->key.offset)) {
967 967 ret = find_first_extent_bit(unpin, start,
968 968 &extent_start, &extent_end,
969   - EXTENT_DIRTY);
  969 + EXTENT_DIRTY, NULL);
970 970 if (ret) {
971 971 ret = 0;
972 972 break;
fs/btrfs/relocation.c
... ... @@ -3621,7 +3621,7 @@
3621 3621  
3622 3622 ret = find_first_extent_bit(&rc->processed_blocks,
3623 3623 key.objectid, &start, &end,
3624   - EXTENT_DIRTY);
  3624 + EXTENT_DIRTY, NULL);
3625 3625  
3626 3626 if (ret == 0 && start <= key.objectid) {
3627 3627 btrfs_release_path(path);
fs/btrfs/transaction.c
... ... @@ -687,13 +687,15 @@
687 687 int err = 0;
688 688 int werr = 0;
689 689 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
  690 + struct extent_state *cached_state = NULL;
690 691 u64 start = 0;
691 692 u64 end;
692 693  
693 694 while (!find_first_extent_bit(dirty_pages, start, &start, &end,
694   - mark)) {
695   - convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT, mark,
696   - GFP_NOFS);
  695 + mark, &cached_state)) {
  696 + convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
  697 + mark, &cached_state, GFP_NOFS);
  698 + cached_state = NULL;
697 699 err = filemap_fdatawrite_range(mapping, start, end);
698 700 if (err)
699 701 werr = err;
700 702  
... ... @@ -717,12 +719,14 @@
717 719 int err = 0;
718 720 int werr = 0;
719 721 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
  722 + struct extent_state *cached_state = NULL;
720 723 u64 start = 0;
721 724 u64 end;
722 725  
723 726 while (!find_first_extent_bit(dirty_pages, start, &start, &end,
724   - EXTENT_NEED_WAIT)) {
725   - clear_extent_bits(dirty_pages, start, end, EXTENT_NEED_WAIT, GFP_NOFS);
  727 + EXTENT_NEED_WAIT, &cached_state)) {
  728 + clear_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
  729 + 0, 0, &cached_state, GFP_NOFS);
726 730 err = filemap_fdatawait_range(mapping, start, end);
727 731 if (err)
728 732 werr = err;
... ... @@ -2463,7 +2463,8 @@
2463 2463  
2464 2464 while (1) {
2465 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 2468 if (ret)
2468 2469 break;
2469 2470