int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, struct btrfs_path *path, iterate_extent_inodes_t *iterate, void *ctx) { int ret; u64 extent_item_pos; u64 flags = 0; struct btrfs_key found_key; int search_commit_root = path->search_commit_root; ret = extent_from_logical(fs_info, logical, path, &found_key, &flags); btrfs_release_path(path); if (ret < 0) return ret; if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) return -EINVAL; extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(fs_info, found_key.objectid, extent_item_pos, search_commit_root, iterate, ctx); return ret; }
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; }