@@ -7132,6 +7132,89 @@ out:
return ret ? ret : nr_del;
}
+/*
+ * Based extent backref item, we find all file extent items in the fs tree. By
+ * the info we can rebuild the extent backref item
+ */
+static int __find_possible_backrefs(struct btrfs_root *root,
+ u64 owner, u64 offset, u64 bytenr, u64 *refs_ret,
+ u64 *bytes_ret)
+{
+ int ret = 0;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct btrfs_file_extent_item *fi;
+ struct extent_buffer *leaf;
+ u64 backref_offset, disk_bytenr;
+ int slot;
+
+ btrfs_init_path(&path);
+
+ key.objectid = owner;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret) {
+ btrfs_release_path(&path);
+ return ret;
+ }
+
+ btrfs_release_path(&path);
+
+ key.objectid = owner;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret < 0) {
+ btrfs_release_path(&path);
+ return ret;
+ }
+
+ while (1) {
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, &path);
+ if (ret) {
+ if (ret > 0)
+ ret = 0;
+ break;
+ }
+
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+ }
+
+ btrfs_item_key_to_cpu(leaf, &found_key, slot);
+ if ((found_key.objectid != owner) ||
+ (found_key.type != BTRFS_EXTENT_DATA_KEY))
+ break;
+
+ fi = btrfs_item_ptr(leaf, slot,
+ struct btrfs_file_extent_item);
+
+ backref_offset = found_key.offset -
+ btrfs_file_extent_offset(leaf, fi);
+ disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+ *bytes_ret = btrfs_file_extent_disk_num_bytes(leaf,
+ fi);
+ if ((disk_bytenr == bytenr) &&
+ (backref_offset == offset)) {
+ (*refs_ret)++;
+ }
+ path.slots[0]++;
+ }
+
+ btrfs_release_path(&path);
+ return ret;
+}
+
static int find_possible_backrefs(struct btrfs_fs_info *info,
struct btrfs_path *path,
struct cache_tree *extent_cache,
@@ -7141,9 +7224,9 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
struct extent_backref *back, *tmp;
struct data_backref *dback;
struct cache_extent *cache;
- struct btrfs_file_extent_item *fi;
struct btrfs_key key;
u64 bytenr, bytes;
+ u64 refs;
int ret;
rbtree_postorder_for_each_entry_safe(back, tmp,
@@ -7171,24 +7254,15 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
if (IS_ERR(root))
return PTR_ERR(root);
- key.objectid = dback->owner;
- key.type = BTRFS_EXTENT_DATA_KEY;
- key.offset = dback->offset;
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
- if (ret) {
- btrfs_release_path(path);
- if (ret < 0)
- return ret;
- /* Didn't find it, we can carry on */
- ret = 0;
+ refs = 0;
+ bytes = 0;
+ ret = __find_possible_backrefs(root, dback->owner,
+ dback->offset, rec->start, &refs, &bytes);
+ if (ret)
continue;
- }
- fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
- struct btrfs_file_extent_item);
- bytenr = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
- bytes = btrfs_file_extent_disk_num_bytes(path->nodes[0], fi);
- btrfs_release_path(path);
+ bytenr = rec->start;
+
cache = lookup_cache_extent(extent_cache, bytenr, 1);
if (cache) {
struct extent_record *tmp;
@@ -7207,7 +7281,7 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
continue;
}
- dback->found_ref += 1;
+ dback->found_ref += refs;
dback->disk_bytenr = bytenr;
dback->bytes = bytes;