Commit 07e1ce09 authored by Liu Bo's avatar Liu Bo Committed by David Sterba
Browse files

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: default avatarHolger Hoffstätte <holger@applied-asynchrony.com>
Signed-off-by: default avatarLiu Bo <bo.liu@linux.alibaba.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 03a1d4c8
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ void __cold extent_map_exit(void)
 */
void extent_map_tree_init(struct extent_map_tree *tree)
{
	tree->map = RB_ROOT;
	tree->map = RB_ROOT_CACHED;
	INIT_LIST_HEAD(&tree->modified_extents);
	rwlock_init(&tree->lock);
}
@@ -90,25 +90,28 @@ static u64 range_end(u64 start, u64 len)
	return start + len;
}

static int tree_insert(struct rb_root *root, struct extent_map *em)
static int tree_insert(struct rb_root_cached *root, struct extent_map *em)
{
	struct rb_node **p = &root->rb_node;
	struct rb_node **p = &root->rb_root.rb_node;
	struct rb_node *parent = NULL;
	struct extent_map *entry = NULL;
	struct rb_node *orig_parent = NULL;
	u64 end = range_end(em->start, em->len);
	bool leftmost = true;

	while (*p) {
		parent = *p;
		entry = rb_entry(parent, struct extent_map, rb_node);

		if (em->start < entry->start)
		if (em->start < entry->start) {
			p = &(*p)->rb_left;
		else if (em->start >= extent_map_end(entry))
		} else if (em->start >= extent_map_end(entry)) {
			p = &(*p)->rb_right;
		else
			leftmost = false;
		} else {
			return -EEXIST;
		}
	}

	orig_parent = parent;
	while (parent && em->start >= extent_map_end(entry)) {
@@ -130,7 +133,7 @@ static int tree_insert(struct rb_root *root, struct extent_map *em)
			return -EEXIST;

	rb_link_node(&em->rb_node, orig_parent, p);
	rb_insert_color(&em->rb_node, root);
	rb_insert_color_cached(&em->rb_node, root, leftmost);
	return 0;
}

@@ -242,7 +245,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
			em->mod_start = merge->mod_start;
			em->generation = max(em->generation, merge->generation);

			rb_erase(&merge->rb_node, &tree->map);
			rb_erase_cached(&merge->rb_node, &tree->map);
			RB_CLEAR_NODE(&merge->rb_node);
			free_extent_map(merge);
		}
@@ -254,7 +257,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
	if (rb && mergable_maps(em, merge)) {
		em->len += merge->len;
		em->block_len += merge->block_len;
		rb_erase(&merge->rb_node, &tree->map);
		rb_erase_cached(&merge->rb_node, &tree->map);
		RB_CLEAR_NODE(&merge->rb_node);
		em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
		em->generation = max(em->generation, merge->generation);
@@ -367,7 +370,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree,
	struct rb_node *next = NULL;
	u64 end = range_end(start, len);

	rb_node = __tree_search(&tree->map, start, &prev, &next);
	rb_node = __tree_search(&tree->map.rb_root, start, &prev, &next);
	if (!rb_node) {
		if (prev)
			rb_node = prev;
@@ -431,7 +434,7 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
{
	WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
	rb_erase(&em->rb_node, &tree->map);
	rb_erase_cached(&em->rb_node, &tree->map);
	if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
		list_del_init(&em->list);
	RB_CLEAR_NODE(&em->rb_node);
@@ -446,7 +449,7 @@ void replace_extent_mapping(struct extent_map_tree *tree,
	ASSERT(extent_map_in_tree(cur));
	if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags))
		list_del_init(&cur->list);
	rb_replace_node(&cur->rb_node, &new->rb_node, &tree->map);
	rb_replace_node_cached(&cur->rb_node, &new->rb_node, &tree->map);
	RB_CLEAR_NODE(&cur->rb_node);

	setup_extent_mapping(tree, new, modified);
+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ struct extent_map {
};

struct extent_map_tree {
	struct rb_root map;
	struct rb_root_cached map;
	struct list_head modified_extents;
	rwlock_t lock;
};
+2 −2
Original line number Diff line number Diff line
@@ -5222,10 +5222,10 @@ static void evict_inode_truncate_pages(struct inode *inode)
	truncate_inode_pages_final(&inode->i_data);

	write_lock(&map_tree->lock);
	while (!RB_EMPTY_ROOT(&map_tree->map)) {
	while (!RB_EMPTY_ROOT(&map_tree->map.rb_root)) {
		struct extent_map *em;

		node = rb_first(&map_tree->map);
		node = rb_first_cached(&map_tree->map);
		em = rb_entry(node, struct extent_map, rb_node);
		clear_bit(EXTENT_FLAG_PINNED, &em->flags);
		clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
+2 −2
Original line number Diff line number Diff line
@@ -12,8 +12,8 @@ static void free_extent_map_tree(struct extent_map_tree *em_tree)
	struct extent_map *em;
	struct rb_node *node;

	while (!RB_EMPTY_ROOT(&em_tree->map)) {
		node = rb_first(&em_tree->map);
	while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) {
		node = rb_first_cached(&em_tree->map);
		em = rb_entry(node, struct extent_map, rb_node);
		remove_extent_mapping(em_tree, em);

+2 −2
Original line number Diff line number Diff line
@@ -1613,7 +1613,7 @@ static u64 find_next_chunk(struct btrfs_fs_info *fs_info)

	em_tree = &fs_info->mapping_tree.map_tree;
	read_lock(&em_tree->lock);
	n = rb_last(&em_tree->map);
	n = rb_last(&em_tree->map.rb_root);
	if (n) {
		em = rb_entry(n, struct extent_map, rb_node);
		ret = em->start + em->len;
@@ -7445,7 +7445,7 @@ static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info)
	int ret = 0;

	read_lock(&em_tree->lock);
	for (node = rb_first(&em_tree->map); node; node = rb_next(node)) {
	for (node = rb_first_cached(&em_tree->map); node; node = rb_next(node)) {
		em = rb_entry(node, struct extent_map, rb_node);
		if (em->map_lookup->num_stripes !=
		    em->map_lookup->verified_stripes) {