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

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
Loading
Loading
Loading
Loading
+62 −129
Original line number Diff line number Diff line
@@ -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) {
		cond_resched();
		eb = path1->nodes[0];

		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];
			}
	for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
		struct extent_buffer *eb;
		struct btrfs_key key;
		int type;

			btrfs_item_key_to_cpu(eb, &key, path1->slots[0]);
			if (key.objectid != cur->bytenr) {
				WARN_ON(exist);
				break;
			}
		cond_resched();
		eb = btrfs_backref_get_eb(iter);

			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;
			}
		}
		key.objectid = iter->bytenr;
		if (btrfs_backref_iter_is_inline_ref(iter)) {
			struct btrfs_extent_inline_ref *iref;

		if (ptr < end) {
			/* update key for inline back ref */
			struct btrfs_extent_inline_ref *iref;
			int type;
			iref = (struct btrfs_extent_inline_ref *)ptr;
			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;
			}
		btrfs_release_path(path);
	}
		if (ptr >= end)
			path1->slots[0]++;
	if (ret < 0) {
		err = ret;
		goto out;
	}
	btrfs_release_path(path1);
	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,