Commit d85327b1 authored by David Sterba's avatar David Sterba

btrfs: prefetch chunk tree leaves at mount

The whole chunk tree is read at mount time so we can utilize readahead
to get the tree blocks to memory before we read the items. The idea is
from Robbie, but instead of updating search slot readahead, this patch
implements the chunk tree readahead manually from nodes on level 1.

We've decided to do specific readahead optimizations and then unify them
under a common API so we don't break everything by changing the search
slot readahead logic.

Higher chunk trees grow on large filesystems (many terabytes), and
prefetching just level 1 seems to be sufficient. Provided example was
from a 200TiB filesystem with chunk tree level 2.

CC: Robbie Ko <robbieko@synology.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 49bac897
...@@ -7013,6 +7013,19 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info, ...@@ -7013,6 +7013,19 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
return ret; return ret;
} }
static void readahead_tree_node_children(struct extent_buffer *node)
{
int i;
const int nr_items = btrfs_header_nritems(node);
for (i = 0; i < nr_items; i++) {
u64 start;
start = btrfs_node_blockptr(node, i);
readahead_tree_block(node->fs_info, start);
}
}
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_root *root = fs_info->chunk_root; struct btrfs_root *root = fs_info->chunk_root;
...@@ -7023,6 +7036,7 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) ...@@ -7023,6 +7036,7 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
int ret; int ret;
int slot; int slot;
u64 total_dev = 0; u64 total_dev = 0;
u64 last_ra_node = 0;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
...@@ -7056,6 +7070,8 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) ...@@ -7056,6 +7070,8 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
if (ret < 0) if (ret < 0)
goto error; goto error;
while (1) { while (1) {
struct extent_buffer *node;
leaf = path->nodes[0]; leaf = path->nodes[0];
slot = path->slots[0]; slot = path->slots[0];
if (slot >= btrfs_header_nritems(leaf)) { if (slot >= btrfs_header_nritems(leaf)) {
...@@ -7066,6 +7082,17 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) ...@@ -7066,6 +7082,17 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
goto error; goto error;
break; break;
} }
/*
* The nodes on level 1 are not locked but we don't need to do
* that during mount time as nothing else can access the tree
*/
node = path->nodes[1];
if (node) {
if (last_ra_node != node->start) {
readahead_tree_node_children(node);
last_ra_node = node->start;
}
}
btrfs_item_key_to_cpu(leaf, &found_key, slot); btrfs_item_key_to_cpu(leaf, &found_key, slot);
if (found_key.type == BTRFS_DEV_ITEM_KEY) { if (found_key.type == BTRFS_DEV_ITEM_KEY) {
struct btrfs_dev_item *dev_item; struct btrfs_dev_item *dev_item;
......
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