diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 123 |
1 files changed, 104 insertions, 19 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 54a201dac7f9..2d3e32ebfd15 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -25,6 +25,9 @@ | |||
25 | #include "delayed-ref.h" | 25 | #include "delayed-ref.h" |
26 | #include "locking.h" | 26 | #include "locking.h" |
27 | 27 | ||
28 | /* Just an arbitrary number so we can be sure this happened */ | ||
29 | #define BACKREF_FOUND_SHARED 6 | ||
30 | |||
28 | struct extent_inode_elem { | 31 | struct extent_inode_elem { |
29 | u64 inum; | 32 | u64 inum; |
30 | u64 offset; | 33 | u64 offset; |
@@ -377,7 +380,8 @@ out: | |||
377 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | 380 | static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, |
378 | struct btrfs_path *path, u64 time_seq, | 381 | struct btrfs_path *path, u64 time_seq, |
379 | struct list_head *head, | 382 | struct list_head *head, |
380 | const u64 *extent_item_pos, u64 total_refs) | 383 | const u64 *extent_item_pos, u64 total_refs, |
384 | u64 root_objectid) | ||
381 | { | 385 | { |
382 | int err; | 386 | int err; |
383 | int ret = 0; | 387 | int ret = 0; |
@@ -402,6 +406,10 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
402 | continue; | 406 | continue; |
403 | if (ref->count == 0) | 407 | if (ref->count == 0) |
404 | continue; | 408 | continue; |
409 | if (root_objectid && ref->root_id != root_objectid) { | ||
410 | ret = BACKREF_FOUND_SHARED; | ||
411 | goto out; | ||
412 | } | ||
405 | err = __resolve_indirect_ref(fs_info, path, time_seq, ref, | 413 | err = __resolve_indirect_ref(fs_info, path, time_seq, ref, |
406 | parents, extent_item_pos, | 414 | parents, extent_item_pos, |
407 | total_refs); | 415 | total_refs); |
@@ -482,7 +490,7 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info, | |||
482 | continue; | 490 | continue; |
483 | BUG_ON(!ref->wanted_disk_byte); | 491 | BUG_ON(!ref->wanted_disk_byte); |
484 | eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte, | 492 | eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte, |
485 | fs_info->tree_root->leafsize, 0); | 493 | 0); |
486 | if (!eb || !extent_buffer_uptodate(eb)) { | 494 | if (!eb || !extent_buffer_uptodate(eb)) { |
487 | free_extent_buffer(eb); | 495 | free_extent_buffer(eb); |
488 | return -EIO; | 496 | return -EIO; |
@@ -561,7 +569,8 @@ static void __merge_refs(struct list_head *head, int mode) | |||
561 | * smaller or equal that seq to the list | 569 | * smaller or equal that seq to the list |
562 | */ | 570 | */ |
563 | static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | 571 | static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, |
564 | struct list_head *prefs, u64 *total_refs) | 572 | struct list_head *prefs, u64 *total_refs, |
573 | u64 inum) | ||
565 | { | 574 | { |
566 | struct btrfs_delayed_extent_op *extent_op = head->extent_op; | 575 | struct btrfs_delayed_extent_op *extent_op = head->extent_op; |
567 | struct rb_node *n = &head->node.rb_node; | 576 | struct rb_node *n = &head->node.rb_node; |
@@ -625,6 +634,16 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
625 | key.objectid = ref->objectid; | 634 | key.objectid = ref->objectid; |
626 | key.type = BTRFS_EXTENT_DATA_KEY; | 635 | key.type = BTRFS_EXTENT_DATA_KEY; |
627 | key.offset = ref->offset; | 636 | key.offset = ref->offset; |
637 | |||
638 | /* | ||
639 | * Found a inum that doesn't match our known inum, we | ||
640 | * know it's shared. | ||
641 | */ | ||
642 | if (inum && ref->objectid != inum) { | ||
643 | ret = BACKREF_FOUND_SHARED; | ||
644 | break; | ||
645 | } | ||
646 | |||
628 | ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, | 647 | ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, |
629 | node->bytenr, | 648 | node->bytenr, |
630 | node->ref_mod * sgn, GFP_ATOMIC); | 649 | node->ref_mod * sgn, GFP_ATOMIC); |
@@ -659,7 +678,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
659 | static int __add_inline_refs(struct btrfs_fs_info *fs_info, | 678 | static int __add_inline_refs(struct btrfs_fs_info *fs_info, |
660 | struct btrfs_path *path, u64 bytenr, | 679 | struct btrfs_path *path, u64 bytenr, |
661 | int *info_level, struct list_head *prefs, | 680 | int *info_level, struct list_head *prefs, |
662 | u64 *total_refs) | 681 | u64 *total_refs, u64 inum) |
663 | { | 682 | { |
664 | int ret = 0; | 683 | int ret = 0; |
665 | int slot; | 684 | int slot; |
@@ -744,6 +763,12 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info, | |||
744 | dref); | 763 | dref); |
745 | key.type = BTRFS_EXTENT_DATA_KEY; | 764 | key.type = BTRFS_EXTENT_DATA_KEY; |
746 | key.offset = btrfs_extent_data_ref_offset(leaf, dref); | 765 | key.offset = btrfs_extent_data_ref_offset(leaf, dref); |
766 | |||
767 | if (inum && key.objectid != inum) { | ||
768 | ret = BACKREF_FOUND_SHARED; | ||
769 | break; | ||
770 | } | ||
771 | |||
747 | root = btrfs_extent_data_ref_root(leaf, dref); | 772 | root = btrfs_extent_data_ref_root(leaf, dref); |
748 | ret = __add_prelim_ref(prefs, root, &key, 0, 0, | 773 | ret = __add_prelim_ref(prefs, root, &key, 0, 0, |
749 | bytenr, count, GFP_NOFS); | 774 | bytenr, count, GFP_NOFS); |
@@ -765,7 +790,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info, | |||
765 | */ | 790 | */ |
766 | static int __add_keyed_refs(struct btrfs_fs_info *fs_info, | 791 | static int __add_keyed_refs(struct btrfs_fs_info *fs_info, |
767 | struct btrfs_path *path, u64 bytenr, | 792 | struct btrfs_path *path, u64 bytenr, |
768 | int info_level, struct list_head *prefs) | 793 | int info_level, struct list_head *prefs, u64 inum) |
769 | { | 794 | { |
770 | struct btrfs_root *extent_root = fs_info->extent_root; | 795 | struct btrfs_root *extent_root = fs_info->extent_root; |
771 | int ret; | 796 | int ret; |
@@ -827,6 +852,12 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
827 | dref); | 852 | dref); |
828 | key.type = BTRFS_EXTENT_DATA_KEY; | 853 | key.type = BTRFS_EXTENT_DATA_KEY; |
829 | key.offset = btrfs_extent_data_ref_offset(leaf, dref); | 854 | key.offset = btrfs_extent_data_ref_offset(leaf, dref); |
855 | |||
856 | if (inum && key.objectid != inum) { | ||
857 | ret = BACKREF_FOUND_SHARED; | ||
858 | break; | ||
859 | } | ||
860 | |||
830 | root = btrfs_extent_data_ref_root(leaf, dref); | 861 | root = btrfs_extent_data_ref_root(leaf, dref); |
831 | ret = __add_prelim_ref(prefs, root, &key, 0, 0, | 862 | ret = __add_prelim_ref(prefs, root, &key, 0, 0, |
832 | bytenr, count, GFP_NOFS); | 863 | bytenr, count, GFP_NOFS); |
@@ -854,7 +885,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
854 | static int find_parent_nodes(struct btrfs_trans_handle *trans, | 885 | static int find_parent_nodes(struct btrfs_trans_handle *trans, |
855 | struct btrfs_fs_info *fs_info, u64 bytenr, | 886 | struct btrfs_fs_info *fs_info, u64 bytenr, |
856 | u64 time_seq, struct ulist *refs, | 887 | u64 time_seq, struct ulist *refs, |
857 | struct ulist *roots, const u64 *extent_item_pos) | 888 | struct ulist *roots, const u64 *extent_item_pos, |
889 | u64 root_objectid, u64 inum) | ||
858 | { | 890 | { |
859 | struct btrfs_key key; | 891 | struct btrfs_key key; |
860 | struct btrfs_path *path; | 892 | struct btrfs_path *path; |
@@ -929,7 +961,8 @@ again: | |||
929 | } | 961 | } |
930 | spin_unlock(&delayed_refs->lock); | 962 | spin_unlock(&delayed_refs->lock); |
931 | ret = __add_delayed_refs(head, time_seq, | 963 | ret = __add_delayed_refs(head, time_seq, |
932 | &prefs_delayed, &total_refs); | 964 | &prefs_delayed, &total_refs, |
965 | inum); | ||
933 | mutex_unlock(&head->mutex); | 966 | mutex_unlock(&head->mutex); |
934 | if (ret) | 967 | if (ret) |
935 | goto out; | 968 | goto out; |
@@ -951,11 +984,11 @@ again: | |||
951 | key.type == BTRFS_METADATA_ITEM_KEY)) { | 984 | key.type == BTRFS_METADATA_ITEM_KEY)) { |
952 | ret = __add_inline_refs(fs_info, path, bytenr, | 985 | ret = __add_inline_refs(fs_info, path, bytenr, |
953 | &info_level, &prefs, | 986 | &info_level, &prefs, |
954 | &total_refs); | 987 | &total_refs, inum); |
955 | if (ret) | 988 | if (ret) |
956 | goto out; | 989 | goto out; |
957 | ret = __add_keyed_refs(fs_info, path, bytenr, | 990 | ret = __add_keyed_refs(fs_info, path, bytenr, |
958 | info_level, &prefs); | 991 | info_level, &prefs, inum); |
959 | if (ret) | 992 | if (ret) |
960 | goto out; | 993 | goto out; |
961 | } | 994 | } |
@@ -971,7 +1004,8 @@ again: | |||
971 | __merge_refs(&prefs, 1); | 1004 | __merge_refs(&prefs, 1); |
972 | 1005 | ||
973 | ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, | 1006 | ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, |
974 | extent_item_pos, total_refs); | 1007 | extent_item_pos, total_refs, |
1008 | root_objectid); | ||
975 | if (ret) | 1009 | if (ret) |
976 | goto out; | 1010 | goto out; |
977 | 1011 | ||
@@ -981,6 +1015,11 @@ again: | |||
981 | ref = list_first_entry(&prefs, struct __prelim_ref, list); | 1015 | ref = list_first_entry(&prefs, struct __prelim_ref, list); |
982 | WARN_ON(ref->count < 0); | 1016 | WARN_ON(ref->count < 0); |
983 | if (roots && ref->count && ref->root_id && ref->parent == 0) { | 1017 | if (roots && ref->count && ref->root_id && ref->parent == 0) { |
1018 | if (root_objectid && ref->root_id != root_objectid) { | ||
1019 | ret = BACKREF_FOUND_SHARED; | ||
1020 | goto out; | ||
1021 | } | ||
1022 | |||
984 | /* no parent == root of tree */ | 1023 | /* no parent == root of tree */ |
985 | ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); | 1024 | ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); |
986 | if (ret < 0) | 1025 | if (ret < 0) |
@@ -989,12 +1028,10 @@ again: | |||
989 | if (ref->count && ref->parent) { | 1028 | if (ref->count && ref->parent) { |
990 | if (extent_item_pos && !ref->inode_list && | 1029 | if (extent_item_pos && !ref->inode_list && |
991 | ref->level == 0) { | 1030 | ref->level == 0) { |
992 | u32 bsz; | ||
993 | struct extent_buffer *eb; | 1031 | struct extent_buffer *eb; |
994 | bsz = btrfs_level_size(fs_info->extent_root, | 1032 | |
995 | ref->level); | ||
996 | eb = read_tree_block(fs_info->extent_root, | 1033 | eb = read_tree_block(fs_info->extent_root, |
997 | ref->parent, bsz, 0); | 1034 | ref->parent, 0); |
998 | if (!eb || !extent_buffer_uptodate(eb)) { | 1035 | if (!eb || !extent_buffer_uptodate(eb)) { |
999 | free_extent_buffer(eb); | 1036 | free_extent_buffer(eb); |
1000 | ret = -EIO; | 1037 | ret = -EIO; |
@@ -1087,7 +1124,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | |||
1087 | return -ENOMEM; | 1124 | return -ENOMEM; |
1088 | 1125 | ||
1089 | ret = find_parent_nodes(trans, fs_info, bytenr, | 1126 | ret = find_parent_nodes(trans, fs_info, bytenr, |
1090 | time_seq, *leafs, NULL, extent_item_pos); | 1127 | time_seq, *leafs, NULL, extent_item_pos, 0, 0); |
1091 | if (ret < 0 && ret != -ENOENT) { | 1128 | if (ret < 0 && ret != -ENOENT) { |
1092 | free_leaf_list(*leafs); | 1129 | free_leaf_list(*leafs); |
1093 | return ret; | 1130 | return ret; |
@@ -1130,7 +1167,7 @@ static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1130 | ULIST_ITER_INIT(&uiter); | 1167 | ULIST_ITER_INIT(&uiter); |
1131 | while (1) { | 1168 | while (1) { |
1132 | ret = find_parent_nodes(trans, fs_info, bytenr, | 1169 | ret = find_parent_nodes(trans, fs_info, bytenr, |
1133 | time_seq, tmp, *roots, NULL); | 1170 | time_seq, tmp, *roots, NULL, 0, 0); |
1134 | if (ret < 0 && ret != -ENOENT) { | 1171 | if (ret < 0 && ret != -ENOENT) { |
1135 | ulist_free(tmp); | 1172 | ulist_free(tmp); |
1136 | ulist_free(*roots); | 1173 | ulist_free(*roots); |
@@ -1161,6 +1198,54 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1161 | return ret; | 1198 | return ret; |
1162 | } | 1199 | } |
1163 | 1200 | ||
1201 | int btrfs_check_shared(struct btrfs_trans_handle *trans, | ||
1202 | struct btrfs_fs_info *fs_info, u64 root_objectid, | ||
1203 | u64 inum, u64 bytenr) | ||
1204 | { | ||
1205 | struct ulist *tmp = NULL; | ||
1206 | struct ulist *roots = NULL; | ||
1207 | struct ulist_iterator uiter; | ||
1208 | struct ulist_node *node; | ||
1209 | struct seq_list elem = {}; | ||
1210 | int ret = 0; | ||
1211 | |||
1212 | tmp = ulist_alloc(GFP_NOFS); | ||
1213 | roots = ulist_alloc(GFP_NOFS); | ||
1214 | if (!tmp || !roots) { | ||
1215 | ulist_free(tmp); | ||
1216 | ulist_free(roots); | ||
1217 | return -ENOMEM; | ||
1218 | } | ||
1219 | |||
1220 | if (trans) | ||
1221 | btrfs_get_tree_mod_seq(fs_info, &elem); | ||
1222 | else | ||
1223 | down_read(&fs_info->commit_root_sem); | ||
1224 | ULIST_ITER_INIT(&uiter); | ||
1225 | while (1) { | ||
1226 | ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, | ||
1227 | roots, NULL, root_objectid, inum); | ||
1228 | if (ret == BACKREF_FOUND_SHARED) { | ||
1229 | ret = 1; | ||
1230 | break; | ||
1231 | } | ||
1232 | if (ret < 0 && ret != -ENOENT) | ||
1233 | break; | ||
1234 | node = ulist_next(tmp, &uiter); | ||
1235 | if (!node) | ||
1236 | break; | ||
1237 | bytenr = node->val; | ||
1238 | cond_resched(); | ||
1239 | } | ||
1240 | if (trans) | ||
1241 | btrfs_put_tree_mod_seq(fs_info, &elem); | ||
1242 | else | ||
1243 | up_read(&fs_info->commit_root_sem); | ||
1244 | ulist_free(tmp); | ||
1245 | ulist_free(roots); | ||
1246 | return ret; | ||
1247 | } | ||
1248 | |||
1164 | /* | 1249 | /* |
1165 | * this makes the path point to (inum INODE_ITEM ioff) | 1250 | * this makes the path point to (inum INODE_ITEM ioff) |
1166 | */ | 1251 | */ |
@@ -1193,7 +1278,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, | |||
1193 | unsigned long ptr; | 1278 | unsigned long ptr; |
1194 | 1279 | ||
1195 | key.objectid = inode_objectid; | 1280 | key.objectid = inode_objectid; |
1196 | btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY); | 1281 | key.type = BTRFS_INODE_EXTREF_KEY; |
1197 | key.offset = start_off; | 1282 | key.offset = start_off; |
1198 | 1283 | ||
1199 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 1284 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
@@ -1233,7 +1318,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, | |||
1233 | ret = -ENOENT; | 1318 | ret = -ENOENT; |
1234 | if (found_key.objectid != inode_objectid) | 1319 | if (found_key.objectid != inode_objectid) |
1235 | break; | 1320 | break; |
1236 | if (btrfs_key_type(&found_key) != BTRFS_INODE_EXTREF_KEY) | 1321 | if (found_key.type != BTRFS_INODE_EXTREF_KEY) |
1237 | break; | 1322 | break; |
1238 | 1323 | ||
1239 | ret = 0; | 1324 | ret = 0; |
@@ -1366,7 +1451,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, | |||
1366 | } | 1451 | } |
1367 | btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); | 1452 | btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); |
1368 | if (found_key->type == BTRFS_METADATA_ITEM_KEY) | 1453 | if (found_key->type == BTRFS_METADATA_ITEM_KEY) |
1369 | size = fs_info->extent_root->leafsize; | 1454 | size = fs_info->extent_root->nodesize; |
1370 | else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) | 1455 | else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) |
1371 | size = found_key->offset; | 1456 | size = found_key->offset; |
1372 | 1457 | ||