diff options
Diffstat (limited to 'fs/btrfs/backref.c')
| -rw-r--r-- | fs/btrfs/backref.c | 72 |
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 | */ |
| 257 | static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | 257 | static 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); |
| 316 | out: | 309 | out: |
| 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 | */ |
| 324 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | 318 | static 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); |
