diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 120 |
1 files changed, 70 insertions, 50 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 290e347b6db3..8bc5e8ccb091 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -36,16 +36,23 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, | |||
36 | u64 extent_item_pos, | 36 | u64 extent_item_pos, |
37 | struct extent_inode_elem **eie) | 37 | struct extent_inode_elem **eie) |
38 | { | 38 | { |
39 | u64 data_offset; | 39 | u64 offset = 0; |
40 | u64 data_len; | ||
41 | struct extent_inode_elem *e; | 40 | struct extent_inode_elem *e; |
42 | 41 | ||
43 | data_offset = btrfs_file_extent_offset(eb, fi); | 42 | if (!btrfs_file_extent_compression(eb, fi) && |
44 | data_len = btrfs_file_extent_num_bytes(eb, fi); | 43 | !btrfs_file_extent_encryption(eb, fi) && |
44 | !btrfs_file_extent_other_encoding(eb, fi)) { | ||
45 | u64 data_offset; | ||
46 | u64 data_len; | ||
45 | 47 | ||
46 | if (extent_item_pos < data_offset || | 48 | data_offset = btrfs_file_extent_offset(eb, fi); |
47 | extent_item_pos >= data_offset + data_len) | 49 | data_len = btrfs_file_extent_num_bytes(eb, fi); |
48 | return 1; | 50 | |
51 | if (extent_item_pos < data_offset || | ||
52 | extent_item_pos >= data_offset + data_len) | ||
53 | return 1; | ||
54 | offset = extent_item_pos - data_offset; | ||
55 | } | ||
49 | 56 | ||
50 | e = kmalloc(sizeof(*e), GFP_NOFS); | 57 | e = kmalloc(sizeof(*e), GFP_NOFS); |
51 | if (!e) | 58 | if (!e) |
@@ -53,7 +60,7 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, | |||
53 | 60 | ||
54 | e->next = *eie; | 61 | e->next = *eie; |
55 | e->inum = key->objectid; | 62 | e->inum = key->objectid; |
56 | e->offset = key->offset + (extent_item_pos - data_offset); | 63 | e->offset = key->offset + offset; |
57 | *eie = e; | 64 | *eie = e; |
58 | 65 | ||
59 | return 0; | 66 | return 0; |
@@ -189,7 +196,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
189 | struct extent_buffer *eb; | 196 | struct extent_buffer *eb; |
190 | struct btrfs_key key; | 197 | struct btrfs_key key; |
191 | struct btrfs_file_extent_item *fi; | 198 | struct btrfs_file_extent_item *fi; |
192 | struct extent_inode_elem *eie = NULL; | 199 | struct extent_inode_elem *eie = NULL, *old = NULL; |
193 | u64 disk_byte; | 200 | u64 disk_byte; |
194 | 201 | ||
195 | if (level != 0) { | 202 | if (level != 0) { |
@@ -223,6 +230,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
223 | 230 | ||
224 | if (disk_byte == wanted_disk_byte) { | 231 | if (disk_byte == wanted_disk_byte) { |
225 | eie = NULL; | 232 | eie = NULL; |
233 | old = NULL; | ||
226 | if (extent_item_pos) { | 234 | if (extent_item_pos) { |
227 | ret = check_extent_in_eb(&key, eb, fi, | 235 | ret = check_extent_in_eb(&key, eb, fi, |
228 | *extent_item_pos, | 236 | *extent_item_pos, |
@@ -230,18 +238,20 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
230 | if (ret < 0) | 238 | if (ret < 0) |
231 | break; | 239 | break; |
232 | } | 240 | } |
233 | if (!ret) { | 241 | if (ret > 0) |
234 | ret = ulist_add(parents, eb->start, | 242 | goto next; |
235 | (uintptr_t)eie, GFP_NOFS); | 243 | ret = ulist_add_merge(parents, eb->start, |
236 | if (ret < 0) | 244 | (uintptr_t)eie, |
237 | break; | 245 | (u64 *)&old, GFP_NOFS); |
238 | if (!extent_item_pos) { | 246 | if (ret < 0) |
239 | ret = btrfs_next_old_leaf(root, path, | 247 | break; |
240 | time_seq); | 248 | if (!ret && extent_item_pos) { |
241 | continue; | 249 | while (old->next) |
242 | } | 250 | old = old->next; |
251 | old->next = eie; | ||
243 | } | 252 | } |
244 | } | 253 | } |
254 | next: | ||
245 | ret = btrfs_next_old_item(root, path, time_seq); | 255 | ret = btrfs_next_old_item(root, path, time_seq); |
246 | } | 256 | } |
247 | 257 | ||
@@ -255,13 +265,11 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
255 | * to a logical address | 265 | * to a logical address |
256 | */ | 266 | */ |
257 | static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | 267 | static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, |
258 | int search_commit_root, | 268 | struct btrfs_path *path, u64 time_seq, |
259 | u64 time_seq, | 269 | struct __prelim_ref *ref, |
260 | struct __prelim_ref *ref, | 270 | struct ulist *parents, |
261 | struct ulist *parents, | 271 | const u64 *extent_item_pos) |
262 | const u64 *extent_item_pos) | ||
263 | { | 272 | { |
264 | struct btrfs_path *path; | ||
265 | struct btrfs_root *root; | 273 | struct btrfs_root *root; |
266 | struct btrfs_key root_key; | 274 | struct btrfs_key root_key; |
267 | struct extent_buffer *eb; | 275 | struct extent_buffer *eb; |
@@ -269,11 +277,6 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
269 | int root_level; | 277 | int root_level; |
270 | int level = ref->level; | 278 | int level = ref->level; |
271 | 279 | ||
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; | 280 | root_key.objectid = ref->root_id; |
278 | root_key.type = BTRFS_ROOT_ITEM_KEY; | 281 | root_key.type = BTRFS_ROOT_ITEM_KEY; |
279 | root_key.offset = (u64)-1; | 282 | root_key.offset = (u64)-1; |
@@ -314,7 +317,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
314 | time_seq, ref->wanted_disk_byte, | 317 | time_seq, ref->wanted_disk_byte, |
315 | extent_item_pos); | 318 | extent_item_pos); |
316 | out: | 319 | out: |
317 | btrfs_free_path(path); | 320 | path->lowest_level = 0; |
321 | btrfs_release_path(path); | ||
318 | return ret; | 322 | return ret; |
319 | } | 323 | } |
320 | 324 | ||
@@ -322,7 +326,7 @@ out: | |||
322 | * resolve all indirect backrefs from the list | 326 | * resolve all indirect backrefs from the list |
323 | */ | 327 | */ |
324 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | 328 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, |
325 | int search_commit_root, u64 time_seq, | 329 | struct btrfs_path *path, u64 time_seq, |
326 | struct list_head *head, | 330 | struct list_head *head, |
327 | const u64 *extent_item_pos) | 331 | const u64 *extent_item_pos) |
328 | { | 332 | { |
@@ -349,9 +353,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
349 | continue; | 353 | continue; |
350 | if (ref->count == 0) | 354 | if (ref->count == 0) |
351 | continue; | 355 | continue; |
352 | err = __resolve_indirect_ref(fs_info, search_commit_root, | 356 | err = __resolve_indirect_ref(fs_info, path, time_seq, ref, |
353 | time_seq, ref, parents, | 357 | parents, extent_item_pos); |
354 | extent_item_pos); | ||
355 | if (err == -ENOMEM) | 358 | if (err == -ENOMEM) |
356 | goto out; | 359 | goto out; |
357 | if (err) | 360 | if (err) |
@@ -604,6 +607,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info, | |||
604 | int slot; | 607 | int slot; |
605 | struct extent_buffer *leaf; | 608 | struct extent_buffer *leaf; |
606 | struct btrfs_key key; | 609 | struct btrfs_key key; |
610 | struct btrfs_key found_key; | ||
607 | unsigned long ptr; | 611 | unsigned long ptr; |
608 | unsigned long end; | 612 | unsigned long end; |
609 | struct btrfs_extent_item *ei; | 613 | struct btrfs_extent_item *ei; |
@@ -621,17 +625,21 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info, | |||
621 | 625 | ||
622 | ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); | 626 | ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); |
623 | flags = btrfs_extent_flags(leaf, ei); | 627 | flags = btrfs_extent_flags(leaf, ei); |
628 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
624 | 629 | ||
625 | ptr = (unsigned long)(ei + 1); | 630 | ptr = (unsigned long)(ei + 1); |
626 | end = (unsigned long)ei + item_size; | 631 | end = (unsigned long)ei + item_size; |
627 | 632 | ||
628 | if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { | 633 | if (found_key.type == BTRFS_EXTENT_ITEM_KEY && |
634 | flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { | ||
629 | struct btrfs_tree_block_info *info; | 635 | struct btrfs_tree_block_info *info; |
630 | 636 | ||
631 | info = (struct btrfs_tree_block_info *)ptr; | 637 | info = (struct btrfs_tree_block_info *)ptr; |
632 | *info_level = btrfs_tree_block_level(leaf, info); | 638 | *info_level = btrfs_tree_block_level(leaf, info); |
633 | ptr += sizeof(struct btrfs_tree_block_info); | 639 | ptr += sizeof(struct btrfs_tree_block_info); |
634 | BUG_ON(ptr > end); | 640 | BUG_ON(ptr > end); |
641 | } else if (found_key.type == BTRFS_METADATA_ITEM_KEY) { | ||
642 | *info_level = found_key.offset; | ||
635 | } else { | 643 | } else { |
636 | BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA)); | 644 | BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA)); |
637 | } | 645 | } |
@@ -795,7 +803,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
795 | struct btrfs_delayed_ref_head *head; | 803 | struct btrfs_delayed_ref_head *head; |
796 | int info_level = 0; | 804 | int info_level = 0; |
797 | int ret; | 805 | int ret; |
798 | int search_commit_root = (trans == BTRFS_BACKREF_SEARCH_COMMIT_ROOT); | ||
799 | struct list_head prefs_delayed; | 806 | struct list_head prefs_delayed; |
800 | struct list_head prefs; | 807 | struct list_head prefs; |
801 | struct __prelim_ref *ref; | 808 | struct __prelim_ref *ref; |
@@ -804,13 +811,17 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
804 | INIT_LIST_HEAD(&prefs_delayed); | 811 | INIT_LIST_HEAD(&prefs_delayed); |
805 | 812 | ||
806 | key.objectid = bytenr; | 813 | key.objectid = bytenr; |
807 | key.type = BTRFS_EXTENT_ITEM_KEY; | ||
808 | key.offset = (u64)-1; | 814 | key.offset = (u64)-1; |
815 | if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) | ||
816 | key.type = BTRFS_METADATA_ITEM_KEY; | ||
817 | else | ||
818 | key.type = BTRFS_EXTENT_ITEM_KEY; | ||
809 | 819 | ||
810 | path = btrfs_alloc_path(); | 820 | path = btrfs_alloc_path(); |
811 | if (!path) | 821 | if (!path) |
812 | return -ENOMEM; | 822 | return -ENOMEM; |
813 | path->search_commit_root = !!search_commit_root; | 823 | if (!trans) |
824 | path->search_commit_root = 1; | ||
814 | 825 | ||
815 | /* | 826 | /* |
816 | * grab both a lock on the path and a lock on the delayed ref head. | 827 | * grab both a lock on the path and a lock on the delayed ref head. |
@@ -825,7 +836,7 @@ again: | |||
825 | goto out; | 836 | goto out; |
826 | BUG_ON(ret == 0); | 837 | BUG_ON(ret == 0); |
827 | 838 | ||
828 | if (trans != BTRFS_BACKREF_SEARCH_COMMIT_ROOT) { | 839 | if (trans) { |
829 | /* | 840 | /* |
830 | * look if there are updates for this ref queued and lock the | 841 | * look if there are updates for this ref queued and lock the |
831 | * head | 842 | * head |
@@ -869,7 +880,8 @@ again: | |||
869 | slot = path->slots[0]; | 880 | slot = path->slots[0]; |
870 | btrfs_item_key_to_cpu(leaf, &key, slot); | 881 | btrfs_item_key_to_cpu(leaf, &key, slot); |
871 | if (key.objectid == bytenr && | 882 | if (key.objectid == bytenr && |
872 | key.type == BTRFS_EXTENT_ITEM_KEY) { | 883 | (key.type == BTRFS_EXTENT_ITEM_KEY || |
884 | key.type == BTRFS_METADATA_ITEM_KEY)) { | ||
873 | ret = __add_inline_refs(fs_info, path, bytenr, | 885 | ret = __add_inline_refs(fs_info, path, bytenr, |
874 | &info_level, &prefs); | 886 | &info_level, &prefs); |
875 | if (ret) | 887 | if (ret) |
@@ -890,8 +902,8 @@ again: | |||
890 | 902 | ||
891 | __merge_refs(&prefs, 1); | 903 | __merge_refs(&prefs, 1); |
892 | 904 | ||
893 | ret = __resolve_indirect_refs(fs_info, search_commit_root, time_seq, | 905 | ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, |
894 | &prefs, extent_item_pos); | 906 | extent_item_pos); |
895 | if (ret) | 907 | if (ret) |
896 | goto out; | 908 | goto out; |
897 | 909 | ||
@@ -1283,12 +1295,16 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, | |||
1283 | { | 1295 | { |
1284 | int ret; | 1296 | int ret; |
1285 | u64 flags; | 1297 | u64 flags; |
1298 | u64 size = 0; | ||
1286 | u32 item_size; | 1299 | u32 item_size; |
1287 | struct extent_buffer *eb; | 1300 | struct extent_buffer *eb; |
1288 | struct btrfs_extent_item *ei; | 1301 | struct btrfs_extent_item *ei; |
1289 | struct btrfs_key key; | 1302 | struct btrfs_key key; |
1290 | 1303 | ||
1291 | key.type = BTRFS_EXTENT_ITEM_KEY; | 1304 | if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) |
1305 | key.type = BTRFS_METADATA_ITEM_KEY; | ||
1306 | else | ||
1307 | key.type = BTRFS_EXTENT_ITEM_KEY; | ||
1292 | key.objectid = logical; | 1308 | key.objectid = logical; |
1293 | key.offset = (u64)-1; | 1309 | key.offset = (u64)-1; |
1294 | 1310 | ||
@@ -1301,9 +1317,15 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, | |||
1301 | return ret; | 1317 | return ret; |
1302 | 1318 | ||
1303 | btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); | 1319 | btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); |
1304 | if (found_key->type != BTRFS_EXTENT_ITEM_KEY || | 1320 | if (found_key->type == BTRFS_METADATA_ITEM_KEY) |
1321 | size = fs_info->extent_root->leafsize; | ||
1322 | else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) | ||
1323 | size = found_key->offset; | ||
1324 | |||
1325 | if ((found_key->type != BTRFS_EXTENT_ITEM_KEY && | ||
1326 | found_key->type != BTRFS_METADATA_ITEM_KEY) || | ||
1305 | found_key->objectid > logical || | 1327 | found_key->objectid > logical || |
1306 | found_key->objectid + found_key->offset <= logical) { | 1328 | found_key->objectid + size <= logical) { |
1307 | pr_debug("logical %llu is not within any extent\n", | 1329 | pr_debug("logical %llu is not within any extent\n", |
1308 | (unsigned long long)logical); | 1330 | (unsigned long long)logical); |
1309 | return -ENOENT; | 1331 | return -ENOENT; |
@@ -1459,7 +1481,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1459 | iterate_extent_inodes_t *iterate, void *ctx) | 1481 | iterate_extent_inodes_t *iterate, void *ctx) |
1460 | { | 1482 | { |
1461 | int ret; | 1483 | int ret; |
1462 | struct btrfs_trans_handle *trans; | 1484 | struct btrfs_trans_handle *trans = NULL; |
1463 | struct ulist *refs = NULL; | 1485 | struct ulist *refs = NULL; |
1464 | struct ulist *roots = NULL; | 1486 | struct ulist *roots = NULL; |
1465 | struct ulist_node *ref_node = NULL; | 1487 | struct ulist_node *ref_node = NULL; |
@@ -1471,9 +1493,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1471 | pr_debug("resolving all inodes for extent %llu\n", | 1493 | pr_debug("resolving all inodes for extent %llu\n", |
1472 | extent_item_objectid); | 1494 | extent_item_objectid); |
1473 | 1495 | ||
1474 | if (search_commit_root) { | 1496 | if (!search_commit_root) { |
1475 | trans = BTRFS_BACKREF_SEARCH_COMMIT_ROOT; | ||
1476 | } else { | ||
1477 | trans = btrfs_join_transaction(fs_info->extent_root); | 1497 | trans = btrfs_join_transaction(fs_info->extent_root); |
1478 | if (IS_ERR(trans)) | 1498 | if (IS_ERR(trans)) |
1479 | return PTR_ERR(trans); | 1499 | return PTR_ERR(trans); |