summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Bo <bo.liu@linux.alibaba.com>2018-08-22 15:51:52 -0400
committerDavid Sterba <dsterba@suse.com>2018-10-15 11:23:33 -0400
commit07e1ce096db3605f3e0c98695df66a51e2be9f05 (patch)
tree3e4a910cd136c1b6666d3be7e33b826dbd016db6
parent03a1d4c891634dd5b98da865fb783e8b22d4d027 (diff)
Btrfs: extent_map: use rb_first_cached
rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). As evict_inode_truncate_pages() removes all extent mapping by always looking for the first rb entry, it's helpful to use rb_first_cached instead. For more details about the optimization see patch "Btrfs: delayed-refs: use rb_first_cached for href_root". Tested-by: Holger Hoffstätte <holger@applied-asynchrony.com> Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/extent_map.c27
-rw-r--r--fs/btrfs/extent_map.h2
-rw-r--r--fs/btrfs/inode.c4
-rw-r--r--fs/btrfs/tests/extent-map-tests.c4
-rw-r--r--fs/btrfs/volumes.c4
5 files changed, 22 insertions, 19 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 2382b949cef8..7eea8b6e2cd3 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -34,7 +34,7 @@ void __cold extent_map_exit(void)
34 */ 34 */
35void extent_map_tree_init(struct extent_map_tree *tree) 35void extent_map_tree_init(struct extent_map_tree *tree)
36{ 36{
37 tree->map = RB_ROOT; 37 tree->map = RB_ROOT_CACHED;
38 INIT_LIST_HEAD(&tree->modified_extents); 38 INIT_LIST_HEAD(&tree->modified_extents);
39 rwlock_init(&tree->lock); 39 rwlock_init(&tree->lock);
40} 40}
@@ -90,24 +90,27 @@ static u64 range_end(u64 start, u64 len)
90 return start + len; 90 return start + len;
91} 91}
92 92
93static int tree_insert(struct rb_root *root, struct extent_map *em) 93static int tree_insert(struct rb_root_cached *root, struct extent_map *em)
94{ 94{
95 struct rb_node **p = &root->rb_node; 95 struct rb_node **p = &root->rb_root.rb_node;
96 struct rb_node *parent = NULL; 96 struct rb_node *parent = NULL;
97 struct extent_map *entry = NULL; 97 struct extent_map *entry = NULL;
98 struct rb_node *orig_parent = NULL; 98 struct rb_node *orig_parent = NULL;
99 u64 end = range_end(em->start, em->len); 99 u64 end = range_end(em->start, em->len);
100 bool leftmost = true;
100 101
101 while (*p) { 102 while (*p) {
102 parent = *p; 103 parent = *p;
103 entry = rb_entry(parent, struct extent_map, rb_node); 104 entry = rb_entry(parent, struct extent_map, rb_node);
104 105
105 if (em->start < entry->start) 106 if (em->start < entry->start) {
106 p = &(*p)->rb_left; 107 p = &(*p)->rb_left;
107 else if (em->start >= extent_map_end(entry)) 108 } else if (em->start >= extent_map_end(entry)) {
108 p = &(*p)->rb_right; 109 p = &(*p)->rb_right;
109 else 110 leftmost = false;
111 } else {
110 return -EEXIST; 112 return -EEXIST;
113 }
111 } 114 }
112 115
113 orig_parent = parent; 116 orig_parent = parent;
@@ -130,7 +133,7 @@ static int tree_insert(struct rb_root *root, struct extent_map *em)
130 return -EEXIST; 133 return -EEXIST;
131 134
132 rb_link_node(&em->rb_node, orig_parent, p); 135 rb_link_node(&em->rb_node, orig_parent, p);
133 rb_insert_color(&em->rb_node, root); 136 rb_insert_color_cached(&em->rb_node, root, leftmost);
134 return 0; 137 return 0;
135} 138}
136 139
@@ -242,7 +245,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
242 em->mod_start = merge->mod_start; 245 em->mod_start = merge->mod_start;
243 em->generation = max(em->generation, merge->generation); 246 em->generation = max(em->generation, merge->generation);
244 247
245 rb_erase(&merge->rb_node, &tree->map); 248 rb_erase_cached(&merge->rb_node, &tree->map);
246 RB_CLEAR_NODE(&merge->rb_node); 249 RB_CLEAR_NODE(&merge->rb_node);
247 free_extent_map(merge); 250 free_extent_map(merge);
248 } 251 }
@@ -254,7 +257,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
254 if (rb && mergable_maps(em, merge)) { 257 if (rb && mergable_maps(em, merge)) {
255 em->len += merge->len; 258 em->len += merge->len;
256 em->block_len += merge->block_len; 259 em->block_len += merge->block_len;
257 rb_erase(&merge->rb_node, &tree->map); 260 rb_erase_cached(&merge->rb_node, &tree->map);
258 RB_CLEAR_NODE(&merge->rb_node); 261 RB_CLEAR_NODE(&merge->rb_node);
259 em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; 262 em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
260 em->generation = max(em->generation, merge->generation); 263 em->generation = max(em->generation, merge->generation);
@@ -367,7 +370,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree,
367 struct rb_node *next = NULL; 370 struct rb_node *next = NULL;
368 u64 end = range_end(start, len); 371 u64 end = range_end(start, len);
369 372
370 rb_node = __tree_search(&tree->map, start, &prev, &next); 373 rb_node = __tree_search(&tree->map.rb_root, start, &prev, &next);
371 if (!rb_node) { 374 if (!rb_node) {
372 if (prev) 375 if (prev)
373 rb_node = prev; 376 rb_node = prev;
@@ -431,7 +434,7 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
431void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) 434void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
432{ 435{
433 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); 436 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
434 rb_erase(&em->rb_node, &tree->map); 437 rb_erase_cached(&em->rb_node, &tree->map);
435 if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) 438 if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
436 list_del_init(&em->list); 439 list_del_init(&em->list);
437 RB_CLEAR_NODE(&em->rb_node); 440 RB_CLEAR_NODE(&em->rb_node);
@@ -446,7 +449,7 @@ void replace_extent_mapping(struct extent_map_tree *tree,
446 ASSERT(extent_map_in_tree(cur)); 449 ASSERT(extent_map_in_tree(cur));
447 if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags)) 450 if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags))
448 list_del_init(&cur->list); 451 list_del_init(&cur->list);
449 rb_replace_node(&cur->rb_node, &new->rb_node, &tree->map); 452 rb_replace_node_cached(&cur->rb_node, &new->rb_node, &tree->map);
450 RB_CLEAR_NODE(&cur->rb_node); 453 RB_CLEAR_NODE(&cur->rb_node);
451 454
452 setup_extent_mapping(tree, new, modified); 455 setup_extent_mapping(tree, new, modified);
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index a7ceb30449fc..31977ffd6190 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -49,7 +49,7 @@ struct extent_map {
49}; 49};
50 50
51struct extent_map_tree { 51struct extent_map_tree {
52 struct rb_root map; 52 struct rb_root_cached map;
53 struct list_head modified_extents; 53 struct list_head modified_extents;
54 rwlock_t lock; 54 rwlock_t lock;
55}; 55};
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8ba7e5d5071e..dd2140d3e354 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5222,10 +5222,10 @@ static void evict_inode_truncate_pages(struct inode *inode)
5222 truncate_inode_pages_final(&inode->i_data); 5222 truncate_inode_pages_final(&inode->i_data);
5223 5223
5224 write_lock(&map_tree->lock); 5224 write_lock(&map_tree->lock);
5225 while (!RB_EMPTY_ROOT(&map_tree->map)) { 5225 while (!RB_EMPTY_ROOT(&map_tree->map.rb_root)) {
5226 struct extent_map *em; 5226 struct extent_map *em;
5227 5227
5228 node = rb_first(&map_tree->map); 5228 node = rb_first_cached(&map_tree->map);
5229 em = rb_entry(node, struct extent_map, rb_node); 5229 em = rb_entry(node, struct extent_map, rb_node);
5230 clear_bit(EXTENT_FLAG_PINNED, &em->flags); 5230 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
5231 clear_bit(EXTENT_FLAG_LOGGING, &em->flags); 5231 clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c
index 385a5316e4bf..bf15d3a7f20e 100644
--- a/fs/btrfs/tests/extent-map-tests.c
+++ b/fs/btrfs/tests/extent-map-tests.c
@@ -12,8 +12,8 @@ static void free_extent_map_tree(struct extent_map_tree *em_tree)
12 struct extent_map *em; 12 struct extent_map *em;
13 struct rb_node *node; 13 struct rb_node *node;
14 14
15 while (!RB_EMPTY_ROOT(&em_tree->map)) { 15 while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) {
16 node = rb_first(&em_tree->map); 16 node = rb_first_cached(&em_tree->map);
17 em = rb_entry(node, struct extent_map, rb_node); 17 em = rb_entry(node, struct extent_map, rb_node);
18 remove_extent_mapping(em_tree, em); 18 remove_extent_mapping(em_tree, em);
19 19
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 86c2330ac83f..909c578506ee 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1613,7 +1613,7 @@ static u64 find_next_chunk(struct btrfs_fs_info *fs_info)
1613 1613
1614 em_tree = &fs_info->mapping_tree.map_tree; 1614 em_tree = &fs_info->mapping_tree.map_tree;
1615 read_lock(&em_tree->lock); 1615 read_lock(&em_tree->lock);
1616 n = rb_last(&em_tree->map); 1616 n = rb_last(&em_tree->map.rb_root);
1617 if (n) { 1617 if (n) {
1618 em = rb_entry(n, struct extent_map, rb_node); 1618 em = rb_entry(n, struct extent_map, rb_node);
1619 ret = em->start + em->len; 1619 ret = em->start + em->len;
@@ -7445,7 +7445,7 @@ static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info)
7445 int ret = 0; 7445 int ret = 0;
7446 7446
7447 read_lock(&em_tree->lock); 7447 read_lock(&em_tree->lock);
7448 for (node = rb_first(&em_tree->map); node; node = rb_next(node)) { 7448 for (node = rb_first_cached(&em_tree->map); node; node = rb_next(node)) {
7449 em = rb_entry(node, struct extent_map, rb_node); 7449 em = rb_entry(node, struct extent_map, rb_node);
7450 if (em->map_lookup->num_stripes != 7450 if (em->map_lookup->num_stripes !=
7451 em->map_lookup->verified_stripes) { 7451 em->map_lookup->verified_stripes) {