Commit 71f572a9 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

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: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent c39c2ddc
...@@ -654,48 +654,6 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info, ...@@ -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); 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 * build backref tree for a given tree block. root of the backref tree
* corresponds the tree block, leaves of the backref tree correspond * corresponds the tree block, leaves of the backref tree correspond
...@@ -715,10 +673,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -715,10 +673,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
struct btrfs_key *node_key, struct btrfs_key *node_key,
int level, u64 bytenr) int level, u64 bytenr)
{ {
struct btrfs_backref_iter *iter;
struct backref_cache *cache = &rc->backref_cache; struct backref_cache *cache = &rc->backref_cache;
struct btrfs_path *path1; /* For searching extent root */ /* For searching parent of TREE_BLOCK_REF */
struct btrfs_path *path2; /* For searching parent of TREE_BLOCK_REF */ struct btrfs_path *path;
struct extent_buffer *eb;
struct btrfs_root *root; struct btrfs_root *root;
struct backref_node *cur; struct backref_node *cur;
struct backref_node *upper; struct backref_node *upper;
...@@ -727,9 +685,6 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -727,9 +685,6 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
struct backref_node *exist = NULL; struct backref_node *exist = NULL;
struct backref_edge *edge; struct backref_edge *edge;
struct rb_node *rb_node; 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(list); /* Pending edge list, upper node needs to be checked */
LIST_HEAD(useless); LIST_HEAD(useless);
int cowonly; int cowonly;
...@@ -737,9 +692,11 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -737,9 +692,11 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
int err = 0; int err = 0;
bool need_check = true; bool need_check = true;
path1 = btrfs_alloc_path(); iter = btrfs_backref_iter_alloc(rc->extent_root->fs_info, GFP_NOFS);
path2 = btrfs_alloc_path(); if (!iter)
if (!path1 || !path2) { return ERR_PTR(-ENOMEM);
path = btrfs_alloc_path();
if (!path) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
...@@ -755,25 +712,28 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -755,25 +712,28 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
node->lowest = 1; node->lowest = 1;
cur = node; cur = node;
again: again:
end = 0; ret = btrfs_backref_iter_start(iter, cur->bytenr);
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);
if (ret < 0) { if (ret < 0) {
err = ret; err = ret;
goto out; 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); WARN_ON(cur->checked);
if (!list_empty(&cur->upper)) { if (!list_empty(&cur->upper)) {
/* /*
...@@ -795,42 +755,21 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -795,42 +755,21 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
exist = NULL; exist = NULL;
} }
while (1) { for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
cond_resched(); struct extent_buffer *eb;
eb = path1->nodes[0]; struct btrfs_key key;
int type;
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]); cond_resched();
if (key.objectid != cur->bytenr) { eb = btrfs_backref_get_eb(iter);
WARN_ON(exist);
break;
}
if (key.type == BTRFS_EXTENT_ITEM_KEY || key.objectid = iter->bytenr;
key.type == BTRFS_METADATA_ITEM_KEY) { if (btrfs_backref_iter_is_inline_ref(iter)) {
ret = find_inline_backref(eb, path1->slots[0], struct btrfs_extent_inline_ref *iref;
&ptr, &end);
if (ret)
goto next;
}
}
if (ptr < end) {
/* update key for inline back ref */ /* update key for inline back ref */
struct btrfs_extent_inline_ref *iref; iref = (struct btrfs_extent_inline_ref *)
int type; ((unsigned long)iter->cur_ptr);
iref = (struct btrfs_extent_inline_ref *)ptr;
type = btrfs_get_extent_inline_ref_type(eb, iref, type = btrfs_get_extent_inline_ref_type(eb, iref,
BTRFS_REF_TYPE_BLOCK); BTRFS_REF_TYPE_BLOCK);
if (type == BTRFS_REF_TYPE_INVALID) { if (type == BTRFS_REF_TYPE_INVALID) {
...@@ -839,9 +778,9 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -839,9 +778,9 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
} }
key.type = type; key.type = type;
key.offset = btrfs_extent_inline_ref_offset(eb, iref); key.offset = btrfs_extent_inline_ref_offset(eb, iref);
} else {
WARN_ON(key.type != BTRFS_TREE_BLOCK_REF_KEY && key.type = iter->cur_key.type;
key.type != BTRFS_SHARED_BLOCK_REF_KEY); key.offset = iter->cur_key.offset;
} }
/* /*
...@@ -854,7 +793,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -854,7 +793,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
(key.type == BTRFS_SHARED_BLOCK_REF_KEY && (key.type == BTRFS_SHARED_BLOCK_REF_KEY &&
exist->bytenr == key.offset))) { exist->bytenr == key.offset))) {
exist = NULL; exist = NULL;
goto next; continue;
} }
/* SHARED_BLOCK_REF means key.offset is the parent bytenr */ /* SHARED_BLOCK_REF means key.offset is the parent bytenr */
...@@ -900,7 +839,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -900,7 +839,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
edge->node[LOWER] = cur; edge->node[LOWER] = cur;
edge->node[UPPER] = upper; edge->node[UPPER] = upper;
goto next; continue;
} else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
err = -EINVAL; err = -EINVAL;
btrfs_print_v0_err(rc->extent_root->fs_info); btrfs_print_v0_err(rc->extent_root->fs_info);
...@@ -908,7 +847,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -908,7 +847,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
NULL); NULL);
goto out; goto out;
} else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) { } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) {
goto next; continue;
} }
/* /*
...@@ -941,21 +880,21 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -941,21 +880,21 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
level = cur->level + 1; level = cur->level + 1;
/* Search the tree to find parent blocks referring the block. */ /* Search the tree to find parent blocks referring the block. */
path2->search_commit_root = 1; path->search_commit_root = 1;
path2->skip_locking = 1; path->skip_locking = 1;
path2->lowest_level = level; path->lowest_level = level;
ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0); ret = btrfs_search_slot(NULL, root, node_key, path, 0, 0);
path2->lowest_level = 0; path->lowest_level = 0;
if (ret < 0) { if (ret < 0) {
btrfs_put_root(root); btrfs_put_root(root);
err = ret; err = ret;
goto out; goto out;
} }
if (ret > 0 && path2->slots[level] > 0) if (ret > 0 && path->slots[level] > 0)
path2->slots[level]--; path->slots[level]--;
eb = path2->nodes[level]; eb = path->nodes[level];
if (btrfs_node_blockptr(eb, path2->slots[level]) != if (btrfs_node_blockptr(eb, path->slots[level]) !=
cur->bytenr) { cur->bytenr) {
btrfs_err(root->fs_info, btrfs_err(root->fs_info,
"couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)", "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
...@@ -972,7 +911,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -972,7 +911,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
/* Add all nodes and edges in the path */ /* Add all nodes and edges in the path */
for (; level < BTRFS_MAX_LEVEL; level++) { for (; level < BTRFS_MAX_LEVEL; level++) {
if (!path2->nodes[level]) { if (!path->nodes[level]) {
ASSERT(btrfs_root_bytenr(&root->root_item) == ASSERT(btrfs_root_bytenr(&root->root_item) ==
lower->bytenr); lower->bytenr);
if (should_ignore_root(root)) { if (should_ignore_root(root)) {
...@@ -991,7 +930,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -991,7 +930,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
goto out; goto out;
} }
eb = path2->nodes[level]; eb = path->nodes[level];
rb_node = tree_search(&cache->rb_root, eb->start); rb_node = tree_search(&cache->rb_root, eb->start);
if (!rb_node) { if (!rb_node) {
upper = alloc_backref_node(cache); upper = alloc_backref_node(cache);
...@@ -1051,20 +990,14 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -1051,20 +990,14 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
lower = upper; lower = upper;
upper = NULL; upper = NULL;
} }
btrfs_release_path(path2); btrfs_release_path(path);
next: }
if (ptr < end) { if (ret < 0) {
ptr += btrfs_extent_inline_ref_size(key.type); err = ret;
if (ptr >= end) { goto out;
WARN_ON(ptr > end);
ptr = 0;
end = 0;
}
}
if (ptr >= end)
path1->slots[0]++;
} }
btrfs_release_path(path1); ret = 0;
btrfs_backref_iter_release(iter);
cur->checked = 1; cur->checked = 1;
WARN_ON(exist); WARN_ON(exist);
...@@ -1182,8 +1115,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -1182,8 +1115,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
} }
} }
out: out:
btrfs_free_path(path1); btrfs_backref_iter_free(iter);
btrfs_free_path(path2); btrfs_free_path(path);
if (err) { if (err) {
while (!list_empty(&useless)) { while (!list_empty(&useless)) {
lower = list_entry(useless.next, lower = list_entry(useless.next,
......
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