forked from Minki/linux
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:
parent
c39c2ddc67
commit
71f572a9e8
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user