/* * resolve an indirect backref in the form (root_id, key, level) * to a logical address */ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 time_seq, struct __prelim_ref *ref, struct ulist *parents, const u64 *extent_item_pos) { struct btrfs_root *root; struct btrfs_key root_key; struct extent_buffer *eb; int ret = 0; int root_level; int level = ref->level; root_key.objectid = ref->root_id; root_key.type = BTRFS_ROOT_ITEM_KEY; root_key.offset = (u64)-1; root = btrfs_read_fs_root_no_name(fs_info, &root_key); if (IS_ERR(root)) { ret = PTR_ERR(root); goto out; } root_level = btrfs_old_root_level(root, time_seq); if (root_level + 1 == level) goto out; path->lowest_level = level; ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq); pr_debug("search slot in root %llu (level %d, ref count %d) returned " "%d for key (%llu %u %llu)\n", (unsigned long long)ref->root_id, level, ref->count, ret, (unsigned long long)ref->key_for_search.objectid, ref->key_for_search.type, (unsigned long long)ref->key_for_search.offset); if (ret < 0) goto out; eb = path->nodes[level]; while (!eb) { if (!level) { WARN_ON(1); ret = 1; goto out; } level--; eb = path->nodes[level]; } ret = add_all_parents(root, path, parents, level, &ref->key_for_search, time_seq, ref->wanted_disk_byte, extent_item_pos); out: path->lowest_level = 0; btrfs_release_path(path); return ret; }
/* * resolve an indirect backref in the form (root_id, key, level) * to a logical address */ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 time_seq, struct __prelim_ref *ref, struct ulist *parents, const u64 *extent_item_pos, u64 total_refs) { struct btrfs_root *root; struct btrfs_key root_key; struct extent_buffer *eb; int ret = 0; int root_level; int level = ref->level; int index; root_key.objectid = ref->root_id; root_key.type = BTRFS_ROOT_ITEM_KEY; root_key.offset = (u64)-1; index = srcu_read_lock(&fs_info->subvol_srcu); root = btrfs_read_fs_root_no_name(fs_info, &root_key); if (IS_ERR(root)) { srcu_read_unlock(&fs_info->subvol_srcu, index); ret = PTR_ERR(root); goto out; } root_level = btrfs_old_root_level(root, time_seq); if (root_level + 1 == level) { srcu_read_unlock(&fs_info->subvol_srcu, index); goto out; } path->lowest_level = level; ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq); /* root node has been locked, we can release @subvol_srcu safely here */ srcu_read_unlock(&fs_info->subvol_srcu, index); pr_debug("search slot in root %llu (level %d, ref count %d) returned " "%d for key (%llu %u %llu)\n", ref->root_id, level, ref->count, ret, ref->key_for_search.objectid, ref->key_for_search.type, ref->key_for_search.offset); if (ret < 0) goto out; eb = path->nodes[level]; while (!eb) { if (WARN_ON(!level)) { ret = 1; goto out; } level--; eb = path->nodes[level]; } ret = add_all_parents(root, path, parents, ref, level, time_seq, extent_item_pos, total_refs); out: path->lowest_level = 0; btrfs_release_path(path); return ret; }