示例#1
0
/*
 * reads the tree block backref for an extent. tree level and root are returned
 * through out_level and out_root. ptr must point to a 0 value for the first
 * call and may be modified (see __get_extent_inline_ref comment).
 * returns 0 if data was provided, 1 if there was no more data to provide or
 * <0 on error.
 */
int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
				struct btrfs_extent_item *ei, u32 item_size,
				u64 *out_root, u8 *out_level)
{
	int ret;
	int type;
	struct btrfs_tree_block_info *info;
	struct btrfs_extent_inline_ref *eiref;

	if (*ptr == (unsigned long)-1)
		return 1;

	while (1) {
		ret = __get_extent_inline_ref(ptr, eb, ei, item_size,
						&eiref, &type);
		if (ret < 0)
			return ret;

		if (type == BTRFS_TREE_BLOCK_REF_KEY ||
		    type == BTRFS_SHARED_BLOCK_REF_KEY)
			break;

		if (ret == 1)
			return 1;
	}

	/* we can treat both ref types equally here */
	info = (struct btrfs_tree_block_info *)(ei + 1);
	*out_root = btrfs_extent_inline_ref_offset(eb, eiref);
	*out_level = btrfs_tree_block_level(eb, info);

	if (ret == 1)
		*ptr = (unsigned long)-1;

	return 0;
}
示例#2
0
文件: backref.c 项目: 454053205/linux
/*
 * calls iterate() for every inode that references the extent identified by
 * the given parameters. will use the path given as a parameter and return it
 * released.
 * when the iterator function returns a non-zero value, iteration stops.
 */
int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
				struct btrfs_path *path,
				u64 extent_item_objectid,
				u64 extent_offset,
				iterate_extent_inodes_t *iterate, void *ctx)
{
	unsigned long ptr = 0;
	int last;
	int ret;
	int type;
	u64 logical;
	u32 item_size;
	struct btrfs_extent_inline_ref *eiref;
	struct btrfs_extent_data_ref *dref;
	struct extent_buffer *eb;
	struct btrfs_extent_item *ei;
	struct btrfs_key key;
	struct list_head data_refs = LIST_HEAD_INIT(data_refs);
	struct list_head shared_refs = LIST_HEAD_INIT(shared_refs);
	struct __data_ref *ref_d;
	struct __shared_ref *ref_s;

	eb = path->nodes[0];
	ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
	item_size = btrfs_item_size_nr(eb, path->slots[0]);

	/* first we iterate the inline refs, ... */
	do {
		last = __get_extent_inline_ref(&ptr, eb, ei, item_size,
						&eiref, &type);
		if (last == -ENOENT) {
			ret = 0;
			break;
		}
		if (last < 0) {
			ret = last;
			break;
		}

		if (type == BTRFS_EXTENT_DATA_REF_KEY) {
			dref = (struct btrfs_extent_data_ref *)(&eiref->offset);
			ret = __data_list_add_eb(&data_refs, eb, dref);
		} else if (type == BTRFS_SHARED_DATA_REF_KEY) {
			logical = btrfs_extent_inline_ref_offset(eb, eiref);
			ret = __shared_list_add(&shared_refs, logical);
		}
	} while (!ret && !last);

	/* ... then we proceed to in-tree references and ... */
	while (!ret) {
		++path->slots[0];
		if (path->slots[0] > btrfs_header_nritems(eb)) {
			ret = btrfs_next_leaf(fs_info->extent_root, path);
			if (ret) {
				if (ret == 1)
					ret = 0; /* we're done */
				break;
			}
			eb = path->nodes[0];
		}
		btrfs_item_key_to_cpu(eb, &key, path->slots[0]);
		if (key.objectid != extent_item_objectid)
			break;
		if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
			dref = btrfs_item_ptr(eb, path->slots[0],
						struct btrfs_extent_data_ref);
			ret = __data_list_add_eb(&data_refs, eb, dref);
		} else if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
示例#3
0
文件: backref.c 项目: 454053205/linux
static int __iter_shared_inline_ref_inodes(struct btrfs_fs_info *fs_info,
					   u64 logical, u64 inum,
					   u64 extent_data_item_offset,
					   u64 extent_offset,
					   struct btrfs_path *path,
					   struct list_head *data_refs,
					   iterate_extent_inodes_t *iterate,
					   void *ctx)
{
	u64 ref_root;
	u32 item_size;
	struct btrfs_key key;
	struct extent_buffer *eb;
	struct btrfs_extent_item *ei;
	struct btrfs_extent_inline_ref *eiref;
	struct __data_ref *ref;
	int ret;
	int type;
	int last;
	unsigned long ptr = 0;

	WARN_ON(!list_empty(data_refs));
	ret = extent_from_logical(fs_info, logical, path, &key);
	if (ret & BTRFS_EXTENT_FLAG_DATA)
		ret = -EIO;
	if (ret < 0)
		goto out;

	eb = path->nodes[0];
	ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
	item_size = btrfs_item_size_nr(eb, path->slots[0]);

	ret = 0;
	ref_root = 0;
	/*
	 * as done in iterate_extent_inodes, we first build a list of refs to
	 * iterate, then free the path and then iterate them to avoid deadlocks.
	 */
	do {
		last = __get_extent_inline_ref(&ptr, eb, ei, item_size,
						&eiref, &type);
		if (last < 0) {
			ret = last;
			goto out;
		}
		if (type == BTRFS_TREE_BLOCK_REF_KEY ||
		    type == BTRFS_SHARED_BLOCK_REF_KEY) {
			ref_root = btrfs_extent_inline_ref_offset(eb, eiref);
			ret = __data_list_add(data_refs, inum,
						extent_data_item_offset,
						ref_root);
		}
	} while (!ret && !last);

	btrfs_release_path(path);

	if (ref_root == 0) {
		printk(KERN_ERR "btrfs: failed to find tree block ref "
			"for shared data backref %llu\n", logical);
		WARN_ON(1);
		ret = -EIO;
	}

out:
	while (!list_empty(data_refs)) {
		ref = list_first_entry(data_refs, struct __data_ref, list);
		list_del(&ref->list);
		if (!ret)
			ret = iterate(ref->inum, extent_offset +
					ref->extent_data_item_offset,
					ref->root, ctx);
		kfree(ref);
	}

	return ret;
}