btrfs: reloc: use btrfs_backref_iter infrastructure

In the core function of relocation, build_backref_tree, it needs to
iterate all backref items of one tree block.

Use btrfs_backref_iter infrastructure to do the loop and make the code
more readable.

The backref items look would be much more easier to read:

	ret = btrfs_backref_iter_start(iter, cur->bytenr);
	for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
		/* The really important work */
	}

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2020-02-14 13:48:20 +08:00 committed by David Sterba
parent c39c2ddc67
commit 71f572a9e8

View File

@ -654,48 +654,6 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,
return btrfs_get_fs_root(fs_info, &key, false);
}
static noinline_for_stack
int find_inline_backref(struct extent_buffer *leaf, int slot,
unsigned long *ptr, unsigned long *end)
{
struct btrfs_key key;
struct btrfs_extent_item *ei;
struct btrfs_tree_block_info *bi;
u32 item_size;
btrfs_item_key_to_cpu(leaf, &key, slot);
item_size = btrfs_item_size_nr(leaf, slot);
if (item_size < sizeof(*ei)) {
btrfs_print_v0_err(leaf->fs_info);
btrfs_handle_fs_error(leaf->fs_info, -EINVAL, NULL);
return 1;
}
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
WARN_ON(!(btrfs_extent_flags(leaf, ei) &
BTRFS_EXTENT_FLAG_TREE_BLOCK));
if (key.type == BTRFS_EXTENT_ITEM_KEY &&
item_size <= sizeof(*ei) + sizeof(*bi)) {
WARN_ON(item_size < sizeof(*ei) + sizeof(*bi));
return 1;
}
if (key.type == BTRFS_METADATA_ITEM_KEY &&
item_size <= sizeof(*ei)) {
WARN_ON(item_size < sizeof(*ei));
return 1;
}
if (key.type == BTRFS_EXTENT_ITEM_KEY) {
bi = (struct btrfs_tree_block_info *)(ei + 1);
*ptr = (unsigned long)(bi + 1);
} else {
*ptr = (unsigned long)(ei + 1);
}
*end = (unsigned long)ei + item_size;
return 0;
}
/*
* build backref tree for a given tree block. root of the backref tree
* corresponds the tree block, leaves of the backref tree correspond
@ -715,10 +673,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
struct btrfs_key *node_key,
int level, u64 bytenr)
{
struct btrfs_backref_iter *iter;
struct backref_cache *cache = &rc->backref_cache;
struct btrfs_path *path1; /* For searching extent root */
struct btrfs_path *path2; /* For searching parent of TREE_BLOCK_REF */
struct extent_buffer *eb;
/* For searching parent of TREE_BLOCK_REF */
struct btrfs_path *path;
struct btrfs_root *root;
struct backref_node *cur;
struct backref_node *upper;
@ -727,9 +685,6 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
struct backref_node *exist = NULL;
struct backref_edge *edge;
struct rb_node *rb_node;
struct btrfs_key key;
unsigned long end;
unsigned long ptr;
LIST_HEAD(list); /* Pending edge list, upper node needs to be checked */
LIST_HEAD(useless);
int cowonly;
@ -737,9 +692,11 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
int err = 0;
bool need_check = true;
path1 = btrfs_alloc_path();
path2 = btrfs_alloc_path();
if (!path1 || !path2) {
iter = btrfs_backref_iter_alloc(rc->extent_root->fs_info, GFP_NOFS);
if (!iter)
return ERR_PTR(-ENOMEM);
path = btrfs_alloc_path();
if (!path) {
err = -ENOMEM;
goto out;
}
@ -755,25 +712,28 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
node->lowest = 1;
cur = node;
again:
end = 0;
ptr = 0;
key.objectid = cur->bytenr;
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = (u64)-1;
path1->search_commit_root = 1;
path1->skip_locking = 1;
ret = btrfs_search_slot(NULL, rc->extent_root, &key, path1,
0, 0);
ret = btrfs_backref_iter_start(iter, cur->bytenr);
if (ret < 0) {
err = ret;
goto out;
}
ASSERT(ret);
ASSERT(path1->slots[0]);
path1->slots[0]--;
/*
* We skip the first btrfs_tree_block_info, as we don't use the key
* stored in it, but fetch it from the tree block
*/
if (btrfs_backref_has_tree_block_info(iter)) {
ret = btrfs_backref_iter_next(iter);
if (ret < 0) {
err = ret;
goto out;
}
/* No extra backref? This means the tree block is corrupted */
if (ret > 0) {
err = -EUCLEAN;
goto out;
}
}
WARN_ON(cur->checked);
if (!list_empty(&cur->upper)) {
/*
@ -795,42 +755,21 @@ again:
exist = NULL;
}
while (1) {
for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
struct extent_buffer *eb;
struct btrfs_key key;
int type;
cond_resched();
eb = path1->nodes[0];
eb = btrfs_backref_get_eb(iter);
if (ptr >= end) {
if (path1->slots[0] >= btrfs_header_nritems(eb)) {
ret = btrfs_next_leaf(rc->extent_root, path1);
if (ret < 0) {
err = ret;
goto out;
}
if (ret > 0)
break;
eb = path1->nodes[0];
}
btrfs_item_key_to_cpu(eb, &key, path1->slots[0]);
if (key.objectid != cur->bytenr) {
WARN_ON(exist);
break;
}
if (key.type == BTRFS_EXTENT_ITEM_KEY ||
key.type == BTRFS_METADATA_ITEM_KEY) {
ret = find_inline_backref(eb, path1->slots[0],
&ptr, &end);
if (ret)
goto next;
}
}
if (ptr < end) {
/* update key for inline back ref */
key.objectid = iter->bytenr;
if (btrfs_backref_iter_is_inline_ref(iter)) {
struct btrfs_extent_inline_ref *iref;
int type;
iref = (struct btrfs_extent_inline_ref *)ptr;
/* update key for inline back ref */
iref = (struct btrfs_extent_inline_ref *)
((unsigned long)iter->cur_ptr);
type = btrfs_get_extent_inline_ref_type(eb, iref,
BTRFS_REF_TYPE_BLOCK);
if (type == BTRFS_REF_TYPE_INVALID) {
@ -839,9 +778,9 @@ again:
}
key.type = type;
key.offset = btrfs_extent_inline_ref_offset(eb, iref);
WARN_ON(key.type != BTRFS_TREE_BLOCK_REF_KEY &&
key.type != BTRFS_SHARED_BLOCK_REF_KEY);
} else {
key.type = iter->cur_key.type;
key.offset = iter->cur_key.offset;
}
/*
@ -854,7 +793,7 @@ again:
(key.type == BTRFS_SHARED_BLOCK_REF_KEY &&
exist->bytenr == key.offset))) {
exist = NULL;
goto next;
continue;
}
/* SHARED_BLOCK_REF means key.offset is the parent bytenr */
@ -900,7 +839,7 @@ again:
edge->node[LOWER] = cur;
edge->node[UPPER] = upper;
goto next;
continue;
} else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
err = -EINVAL;
btrfs_print_v0_err(rc->extent_root->fs_info);
@ -908,7 +847,7 @@ again:
NULL);
goto out;
} else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) {
goto next;
continue;
}
/*
@ -941,21 +880,21 @@ again:
level = cur->level + 1;
/* Search the tree to find parent blocks referring the block. */
path2->search_commit_root = 1;
path2->skip_locking = 1;
path2->lowest_level = level;
ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0);
path2->lowest_level = 0;
path->search_commit_root = 1;
path->skip_locking = 1;
path->lowest_level = level;
ret = btrfs_search_slot(NULL, root, node_key, path, 0, 0);
path->lowest_level = 0;
if (ret < 0) {
btrfs_put_root(root);
err = ret;
goto out;
}
if (ret > 0 && path2->slots[level] > 0)
path2->slots[level]--;
if (ret > 0 && path->slots[level] > 0)
path->slots[level]--;
eb = path2->nodes[level];
if (btrfs_node_blockptr(eb, path2->slots[level]) !=
eb = path->nodes[level];
if (btrfs_node_blockptr(eb, path->slots[level]) !=
cur->bytenr) {
btrfs_err(root->fs_info,
"couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
@ -972,7 +911,7 @@ again:
/* Add all nodes and edges in the path */
for (; level < BTRFS_MAX_LEVEL; level++) {
if (!path2->nodes[level]) {
if (!path->nodes[level]) {
ASSERT(btrfs_root_bytenr(&root->root_item) ==
lower->bytenr);
if (should_ignore_root(root)) {
@ -991,7 +930,7 @@ again:
goto out;
}
eb = path2->nodes[level];
eb = path->nodes[level];
rb_node = tree_search(&cache->rb_root, eb->start);
if (!rb_node) {
upper = alloc_backref_node(cache);
@ -1051,20 +990,14 @@ again:
lower = upper;
upper = NULL;
}
btrfs_release_path(path2);
next:
if (ptr < end) {
ptr += btrfs_extent_inline_ref_size(key.type);
if (ptr >= end) {
WARN_ON(ptr > end);
ptr = 0;
end = 0;
}
}
if (ptr >= end)
path1->slots[0]++;
btrfs_release_path(path);
}
btrfs_release_path(path1);
if (ret < 0) {
err = ret;
goto out;
}
ret = 0;
btrfs_backref_iter_release(iter);
cur->checked = 1;
WARN_ON(exist);
@ -1182,8 +1115,8 @@ next:
}
}
out:
btrfs_free_path(path1);
btrfs_free_path(path2);
btrfs_backref_iter_free(iter);
btrfs_free_path(path);
if (err) {
while (!list_empty(&useless)) {
lower = list_entry(useless.next,