diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 109 |
1 files changed, 98 insertions, 11 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 4de97926939e..6829dc5aa657 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); |
@@ -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) |
@@ -1087,7 +1126,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | |||
1087 | return -ENOMEM; | 1126 | return -ENOMEM; |
1088 | 1127 | ||
1089 | ret = find_parent_nodes(trans, fs_info, bytenr, | 1128 | ret = find_parent_nodes(trans, fs_info, bytenr, |
1090 | time_seq, *leafs, NULL, extent_item_pos); | 1129 | time_seq, *leafs, NULL, extent_item_pos, 0, 0); |
1091 | if (ret < 0 && ret != -ENOENT) { | 1130 | if (ret < 0 && ret != -ENOENT) { |
1092 | free_leaf_list(*leafs); | 1131 | free_leaf_list(*leafs); |
1093 | return ret; | 1132 | return ret; |
@@ -1130,7 +1169,7 @@ static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1130 | ULIST_ITER_INIT(&uiter); | 1169 | ULIST_ITER_INIT(&uiter); |
1131 | while (1) { | 1170 | while (1) { |
1132 | ret = find_parent_nodes(trans, fs_info, bytenr, | 1171 | ret = find_parent_nodes(trans, fs_info, bytenr, |
1133 | time_seq, tmp, *roots, NULL); | 1172 | time_seq, tmp, *roots, NULL, 0, 0); |
1134 | if (ret < 0 && ret != -ENOENT) { | 1173 | if (ret < 0 && ret != -ENOENT) { |
1135 | ulist_free(tmp); | 1174 | ulist_free(tmp); |
1136 | ulist_free(*roots); | 1175 | ulist_free(*roots); |
@@ -1161,6 +1200,54 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1161 | return ret; | 1200 | return ret; |
1162 | } | 1201 | } |
1163 | 1202 | ||
1203 | int btrfs_check_shared(struct btrfs_trans_handle *trans, | ||
1204 | struct btrfs_fs_info *fs_info, u64 root_objectid, | ||
1205 | u64 inum, u64 bytenr) | ||
1206 | { | ||
1207 | struct ulist *tmp = NULL; | ||
1208 | struct ulist *roots = NULL; | ||
1209 | struct ulist_iterator uiter; | ||
1210 | struct ulist_node *node; | ||
1211 | struct seq_list elem = {}; | ||
1212 | int ret = 0; | ||
1213 | |||
1214 | tmp = ulist_alloc(GFP_NOFS); | ||
1215 | roots = ulist_alloc(GFP_NOFS); | ||
1216 | if (!tmp || !roots) { | ||
1217 | ulist_free(tmp); | ||
1218 | ulist_free(roots); | ||
1219 | return -ENOMEM; | ||
1220 | } | ||
1221 | |||
1222 | if (trans) | ||
1223 | btrfs_get_tree_mod_seq(fs_info, &elem); | ||
1224 | else | ||
1225 | down_read(&fs_info->commit_root_sem); | ||
1226 | ULIST_ITER_INIT(&uiter); | ||
1227 | while (1) { | ||
1228 | ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, | ||
1229 | roots, NULL, root_objectid, inum); | ||
1230 | if (ret == BACKREF_FOUND_SHARED) { | ||
1231 | ret = 1; | ||
1232 | break; | ||
1233 | } | ||
1234 | if (ret < 0 && ret != -ENOENT) | ||
1235 | break; | ||
1236 | node = ulist_next(tmp, &uiter); | ||
1237 | if (!node) | ||
1238 | break; | ||
1239 | bytenr = node->val; | ||
1240 | cond_resched(); | ||
1241 | } | ||
1242 | if (trans) | ||
1243 | btrfs_put_tree_mod_seq(fs_info, &elem); | ||
1244 | else | ||
1245 | up_read(&fs_info->commit_root_sem); | ||
1246 | ulist_free(tmp); | ||
1247 | ulist_free(roots); | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1164 | /* | 1251 | /* |
1165 | * this makes the path point to (inum INODE_ITEM ioff) | 1252 | * this makes the path point to (inum INODE_ITEM ioff) |
1166 | */ | 1253 | */ |