Commit 68a505bb authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

btrfs: more efficient chunk map iteration when device replace finishes

When iterating the chunk maps when a device replace finishes we are doing
a full rbtree search for each chunk map, which is not the most efficient
thing to do, wasting CPU time. As we are holding a write lock on the tree
during the whole iteration, we can simply start from the first node in the
tree and then move to the next chunk map by doing a rb_next() call - the
only exception is when we need to reschedule, in which case we have to do
a full rbtree search since we dropped the write lock and the tree may have
changed (chunk maps may have been removed and the tree got rebalanced).
So just do that.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent b79f1c2c
...@@ -824,8 +824,7 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( ...@@ -824,8 +824,7 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
struct btrfs_device *srcdev, struct btrfs_device *srcdev,
struct btrfs_device *tgtdev) struct btrfs_device *tgtdev)
{ {
u64 start = 0; struct rb_node *node;
int i;
/* /*
* The chunk mutex must be held so that no new chunks can be created * The chunk mutex must be held so that no new chunks can be created
...@@ -836,19 +835,34 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( ...@@ -836,19 +835,34 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
lockdep_assert_held(&fs_info->chunk_mutex); lockdep_assert_held(&fs_info->chunk_mutex);
write_lock(&fs_info->mapping_tree_lock); write_lock(&fs_info->mapping_tree_lock);
do { node = rb_first_cached(&fs_info->mapping_tree);
while (node) {
struct rb_node *next = rb_next(node);
struct btrfs_chunk_map *map; struct btrfs_chunk_map *map;
u64 next_start;
map = btrfs_find_chunk_map_nolock(fs_info, start, U64_MAX); map = rb_entry(node, struct btrfs_chunk_map, rb_node);
if (!map) next_start = map->start + map->chunk_len;
break;
for (i = 0; i < map->num_stripes; i++) for (int i = 0; i < map->num_stripes; i++)
if (srcdev == map->stripes[i].dev) if (srcdev == map->stripes[i].dev)
map->stripes[i].dev = tgtdev; map->stripes[i].dev = tgtdev;
start = map->start + map->chunk_len;
btrfs_free_chunk_map(map); if (cond_resched_rwlock_write(&fs_info->mapping_tree_lock)) {
cond_resched_rwlock_write(&fs_info->mapping_tree_lock); map = btrfs_find_chunk_map_nolock(fs_info, next_start, U64_MAX);
} while (start); if (!map)
break;
node = &map->rb_node;
/*
* Drop the lookup reference since we are holding the
* lock in write mode and no one can remove the chunk
* map from the tree and drop its tree reference.
*/
btrfs_free_chunk_map(map);
} else {
node = next;
}
}
write_unlock(&fs_info->mapping_tree_lock); write_unlock(&fs_info->mapping_tree_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment