aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/backref.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r--fs/btrfs/backref.c72
1 files changed, 41 insertions, 31 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 290e347b6db3..eaf133384a8f 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -255,13 +255,11 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
255 * to a logical address 255 * to a logical address
256 */ 256 */
257static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, 257static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
258 int search_commit_root, 258 struct btrfs_path *path, u64 time_seq,
259 u64 time_seq, 259 struct __prelim_ref *ref,
260 struct __prelim_ref *ref, 260 struct ulist *parents,
261 struct ulist *parents, 261 const u64 *extent_item_pos)
262 const u64 *extent_item_pos)
263{ 262{
264 struct btrfs_path *path;
265 struct btrfs_root *root; 263 struct btrfs_root *root;
266 struct btrfs_key root_key; 264 struct btrfs_key root_key;
267 struct extent_buffer *eb; 265 struct extent_buffer *eb;
@@ -269,11 +267,6 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
269 int root_level; 267 int root_level;
270 int level = ref->level; 268 int level = ref->level;
271 269
272 path = btrfs_alloc_path();
273 if (!path)
274 return -ENOMEM;
275 path->search_commit_root = !!search_commit_root;
276
277 root_key.objectid = ref->root_id; 270 root_key.objectid = ref->root_id;
278 root_key.type = BTRFS_ROOT_ITEM_KEY; 271 root_key.type = BTRFS_ROOT_ITEM_KEY;
279 root_key.offset = (u64)-1; 272 root_key.offset = (u64)-1;
@@ -314,7 +307,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
314 time_seq, ref->wanted_disk_byte, 307 time_seq, ref->wanted_disk_byte,
315 extent_item_pos); 308 extent_item_pos);
316out: 309out:
317 btrfs_free_path(path); 310 path->lowest_level = 0;
311 btrfs_release_path(path);
318 return ret; 312 return ret;
319} 313}
320 314
@@ -322,7 +316,7 @@ out:
322 * resolve all indirect backrefs from the list 316 * resolve all indirect backrefs from the list
323 */ 317 */
324static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, 318static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
325 int search_commit_root, u64 time_seq, 319 struct btrfs_path *path, u64 time_seq,
326 struct list_head *head, 320 struct list_head *head,
327 const u64 *extent_item_pos) 321 const u64 *extent_item_pos)
328{ 322{
@@ -349,9 +343,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
349 continue; 343 continue;
350 if (ref->count == 0) 344 if (ref->count == 0)
351 continue; 345 continue;
352 err = __resolve_indirect_ref(fs_info, search_commit_root, 346 err = __resolve_indirect_ref(fs_info, path, time_seq, ref,
353 time_seq, ref, parents, 347 parents, extent_item_pos);
354 extent_item_pos);
355 if (err == -ENOMEM) 348 if (err == -ENOMEM)
356 goto out; 349 goto out;
357 if (err) 350 if (err)
@@ -604,6 +597,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
604 int slot; 597 int slot;
605 struct extent_buffer *leaf; 598 struct extent_buffer *leaf;
606 struct btrfs_key key; 599 struct btrfs_key key;
600 struct btrfs_key found_key;
607 unsigned long ptr; 601 unsigned long ptr;
608 unsigned long end; 602 unsigned long end;
609 struct btrfs_extent_item *ei; 603 struct btrfs_extent_item *ei;
@@ -621,17 +615,21 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
621 615
622 ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); 616 ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
623 flags = btrfs_extent_flags(leaf, ei); 617 flags = btrfs_extent_flags(leaf, ei);
618 btrfs_item_key_to_cpu(leaf, &found_key, slot);
624 619
625 ptr = (unsigned long)(ei + 1); 620 ptr = (unsigned long)(ei + 1);
626 end = (unsigned long)ei + item_size; 621 end = (unsigned long)ei + item_size;
627 622
628 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { 623 if (found_key.type == BTRFS_EXTENT_ITEM_KEY &&
624 flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
629 struct btrfs_tree_block_info *info; 625 struct btrfs_tree_block_info *info;
630 626
631 info = (struct btrfs_tree_block_info *)ptr; 627 info = (struct btrfs_tree_block_info *)ptr;
632 *info_level = btrfs_tree_block_level(leaf, info); 628 *info_level = btrfs_tree_block_level(leaf, info);
633 ptr += sizeof(struct btrfs_tree_block_info); 629 ptr += sizeof(struct btrfs_tree_block_info);
634 BUG_ON(ptr > end); 630 BUG_ON(ptr > end);
631 } else if (found_key.type == BTRFS_METADATA_ITEM_KEY) {
632 *info_level = found_key.offset;
635 } else { 633 } else {
636 BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA)); 634 BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA));
637 } 635 }
@@ -795,7 +793,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
795 struct btrfs_delayed_ref_head *head; 793 struct btrfs_delayed_ref_head *head;
796 int info_level = 0; 794 int info_level = 0;
797 int ret; 795 int ret;
798 int search_commit_root = (trans == BTRFS_BACKREF_SEARCH_COMMIT_ROOT);
799 struct list_head prefs_delayed; 796 struct list_head prefs_delayed;
800 struct list_head prefs; 797 struct list_head prefs;
801 struct __prelim_ref *ref; 798 struct __prelim_ref *ref;
@@ -804,13 +801,17 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
804 INIT_LIST_HEAD(&prefs_delayed); 801 INIT_LIST_HEAD(&prefs_delayed);
805 802
806 key.objectid = bytenr; 803 key.objectid = bytenr;
807 key.type = BTRFS_EXTENT_ITEM_KEY;
808 key.offset = (u64)-1; 804 key.offset = (u64)-1;
805 if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
806 key.type = BTRFS_METADATA_ITEM_KEY;
807 else
808 key.type = BTRFS_EXTENT_ITEM_KEY;
809 809
810 path = btrfs_alloc_path(); 810 path = btrfs_alloc_path();
811 if (!path) 811 if (!path)
812 return -ENOMEM; 812 return -ENOMEM;
813 path->search_commit_root = !!search_commit_root; 813 if (!trans)
814 path->search_commit_root = 1;
814 815
815 /* 816 /*
816 * grab both a lock on the path and a lock on the delayed ref head. 817 * grab both a lock on the path and a lock on the delayed ref head.
@@ -825,7 +826,7 @@ again:
825 goto out; 826 goto out;
826 BUG_ON(ret == 0); 827 BUG_ON(ret == 0);
827 828
828 if (trans != BTRFS_BACKREF_SEARCH_COMMIT_ROOT) { 829 if (trans) {
829 /* 830 /*
830 * look if there are updates for this ref queued and lock the 831 * look if there are updates for this ref queued and lock the
831 * head 832 * head
@@ -869,7 +870,8 @@ again:
869 slot = path->slots[0]; 870 slot = path->slots[0];
870 btrfs_item_key_to_cpu(leaf, &key, slot); 871 btrfs_item_key_to_cpu(leaf, &key, slot);
871 if (key.objectid == bytenr && 872 if (key.objectid == bytenr &&
872 key.type == BTRFS_EXTENT_ITEM_KEY) { 873 (key.type == BTRFS_EXTENT_ITEM_KEY ||
874 key.type == BTRFS_METADATA_ITEM_KEY)) {
873 ret = __add_inline_refs(fs_info, path, bytenr, 875 ret = __add_inline_refs(fs_info, path, bytenr,
874 &info_level, &prefs); 876 &info_level, &prefs);
875 if (ret) 877 if (ret)
@@ -890,8 +892,8 @@ again:
890 892
891 __merge_refs(&prefs, 1); 893 __merge_refs(&prefs, 1);
892 894
893 ret = __resolve_indirect_refs(fs_info, search_commit_root, time_seq, 895 ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs,
894 &prefs, extent_item_pos); 896 extent_item_pos);
895 if (ret) 897 if (ret)
896 goto out; 898 goto out;
897 899
@@ -1283,12 +1285,16 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
1283{ 1285{
1284 int ret; 1286 int ret;
1285 u64 flags; 1287 u64 flags;
1288 u64 size = 0;
1286 u32 item_size; 1289 u32 item_size;
1287 struct extent_buffer *eb; 1290 struct extent_buffer *eb;
1288 struct btrfs_extent_item *ei; 1291 struct btrfs_extent_item *ei;
1289 struct btrfs_key key; 1292 struct btrfs_key key;
1290 1293
1291 key.type = BTRFS_EXTENT_ITEM_KEY; 1294 if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
1295 key.type = BTRFS_METADATA_ITEM_KEY;
1296 else
1297 key.type = BTRFS_EXTENT_ITEM_KEY;
1292 key.objectid = logical; 1298 key.objectid = logical;
1293 key.offset = (u64)-1; 1299 key.offset = (u64)-1;
1294 1300
@@ -1301,9 +1307,15 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
1301 return ret; 1307 return ret;
1302 1308
1303 btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); 1309 btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);
1304 if (found_key->type != BTRFS_EXTENT_ITEM_KEY || 1310 if (found_key->type == BTRFS_METADATA_ITEM_KEY)
1311 size = fs_info->extent_root->leafsize;
1312 else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)
1313 size = found_key->offset;
1314
1315 if ((found_key->type != BTRFS_EXTENT_ITEM_KEY &&
1316 found_key->type != BTRFS_METADATA_ITEM_KEY) ||
1305 found_key->objectid > logical || 1317 found_key->objectid > logical ||
1306 found_key->objectid + found_key->offset <= logical) { 1318 found_key->objectid + size <= logical) {
1307 pr_debug("logical %llu is not within any extent\n", 1319 pr_debug("logical %llu is not within any extent\n",
1308 (unsigned long long)logical); 1320 (unsigned long long)logical);
1309 return -ENOENT; 1321 return -ENOENT;
@@ -1459,7 +1471,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
1459 iterate_extent_inodes_t *iterate, void *ctx) 1471 iterate_extent_inodes_t *iterate, void *ctx)
1460{ 1472{
1461 int ret; 1473 int ret;
1462 struct btrfs_trans_handle *trans; 1474 struct btrfs_trans_handle *trans = NULL;
1463 struct ulist *refs = NULL; 1475 struct ulist *refs = NULL;
1464 struct ulist *roots = NULL; 1476 struct ulist *roots = NULL;
1465 struct ulist_node *ref_node = NULL; 1477 struct ulist_node *ref_node = NULL;
@@ -1471,9 +1483,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
1471 pr_debug("resolving all inodes for extent %llu\n", 1483 pr_debug("resolving all inodes for extent %llu\n",
1472 extent_item_objectid); 1484 extent_item_objectid);
1473 1485
1474 if (search_commit_root) { 1486 if (!search_commit_root) {
1475 trans = BTRFS_BACKREF_SEARCH_COMMIT_ROOT;
1476 } else {
1477 trans = btrfs_join_transaction(fs_info->extent_root); 1487 trans = btrfs_join_transaction(fs_info->extent_root);
1478 if (IS_ERR(trans)) 1488 if (IS_ERR(trans))
1479 return PTR_ERR(trans); 1489 return PTR_ERR(trans);