diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 118 |
1 files changed, 60 insertions, 58 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 297f33850425..4cda81964dd4 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | #include <linux/rbtree.h> | 20 | #include <linux/rbtree.h> |
21 | #include <trace/events/btrfs.h> | ||
21 | #include "ctree.h" | 22 | #include "ctree.h" |
22 | #include "disk-io.h" | 23 | #include "disk-io.h" |
23 | #include "backref.h" | 24 | #include "backref.h" |
@@ -120,20 +121,6 @@ static int find_extent_in_eb(const struct extent_buffer *eb, | |||
120 | return 0; | 121 | return 0; |
121 | } | 122 | } |
122 | 123 | ||
123 | /* | ||
124 | * this structure records all encountered refs on the way up to the root | ||
125 | */ | ||
126 | struct prelim_ref { | ||
127 | struct rb_node rbnode; | ||
128 | u64 root_id; | ||
129 | struct btrfs_key key_for_search; | ||
130 | int level; | ||
131 | int count; | ||
132 | struct extent_inode_elem *inode_list; | ||
133 | u64 parent; | ||
134 | u64 wanted_disk_byte; | ||
135 | }; | ||
136 | |||
137 | struct preftree { | 124 | struct preftree { |
138 | struct rb_root root; | 125 | struct rb_root root; |
139 | unsigned int count; | 126 | unsigned int count; |
@@ -212,7 +199,8 @@ static int prelim_ref_compare(struct prelim_ref *ref1, | |||
212 | * | 199 | * |
213 | * Callers should assumed that newref has been freed after calling. | 200 | * Callers should assumed that newref has been freed after calling. |
214 | */ | 201 | */ |
215 | static void prelim_ref_insert(struct preftree *preftree, | 202 | static void prelim_ref_insert(const struct btrfs_fs_info *fs_info, |
203 | struct preftree *preftree, | ||
216 | struct prelim_ref *newref) | 204 | struct prelim_ref *newref) |
217 | { | 205 | { |
218 | struct rb_root *root; | 206 | struct rb_root *root; |
@@ -243,6 +231,8 @@ static void prelim_ref_insert(struct preftree *preftree, | |||
243 | ref->inode_list = newref->inode_list; | 231 | ref->inode_list = newref->inode_list; |
244 | else | 232 | else |
245 | eie->next = newref->inode_list; | 233 | eie->next = newref->inode_list; |
234 | trace_btrfs_prelim_ref_merge(fs_info, ref, newref, | ||
235 | preftree->count); | ||
246 | ref->count += newref->count; | 236 | ref->count += newref->count; |
247 | free_pref(newref); | 237 | free_pref(newref); |
248 | return; | 238 | return; |
@@ -250,6 +240,7 @@ static void prelim_ref_insert(struct preftree *preftree, | |||
250 | } | 240 | } |
251 | 241 | ||
252 | preftree->count++; | 242 | preftree->count++; |
243 | trace_btrfs_prelim_ref_insert(fs_info, newref, NULL, preftree->count); | ||
253 | rb_link_node(&newref->rbnode, parent, p); | 244 | rb_link_node(&newref->rbnode, parent, p); |
254 | rb_insert_color(&newref->rbnode, root); | 245 | rb_insert_color(&newref->rbnode, root); |
255 | } | 246 | } |
@@ -308,7 +299,8 @@ static void prelim_release(struct preftree *preftree) | |||
308 | * additional information that's available but not required to find the parent | 299 | * additional information that's available but not required to find the parent |
309 | * block might help in merging entries to gain some speed. | 300 | * block might help in merging entries to gain some speed. |
310 | */ | 301 | */ |
311 | static int add_prelim_ref(struct preftree *preftree, u64 root_id, | 302 | static int add_prelim_ref(const struct btrfs_fs_info *fs_info, |
303 | struct preftree *preftree, u64 root_id, | ||
312 | const struct btrfs_key *key, int level, u64 parent, | 304 | const struct btrfs_key *key, int level, u64 parent, |
313 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) | 305 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) |
314 | { | 306 | { |
@@ -355,21 +347,23 @@ static int add_prelim_ref(struct preftree *preftree, u64 root_id, | |||
355 | ref->count = count; | 347 | ref->count = count; |
356 | ref->parent = parent; | 348 | ref->parent = parent; |
357 | ref->wanted_disk_byte = wanted_disk_byte; | 349 | ref->wanted_disk_byte = wanted_disk_byte; |
358 | prelim_ref_insert(preftree, ref); | 350 | prelim_ref_insert(fs_info, preftree, ref); |
359 | 351 | ||
360 | return 0; | 352 | return 0; |
361 | } | 353 | } |
362 | 354 | ||
363 | /* direct refs use root == 0, key == NULL */ | 355 | /* direct refs use root == 0, key == NULL */ |
364 | static int add_direct_ref(struct preftrees *preftrees, int level, u64 parent, | 356 | static int add_direct_ref(const struct btrfs_fs_info *fs_info, |
357 | struct preftrees *preftrees, int level, u64 parent, | ||
365 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) | 358 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) |
366 | { | 359 | { |
367 | return add_prelim_ref(&preftrees->direct, 0, NULL, level, parent, | 360 | return add_prelim_ref(fs_info, &preftrees->direct, 0, NULL, level, |
368 | wanted_disk_byte, count, gfp_mask); | 361 | parent, wanted_disk_byte, count, gfp_mask); |
369 | } | 362 | } |
370 | 363 | ||
371 | /* indirect refs use parent == 0 */ | 364 | /* indirect refs use parent == 0 */ |
372 | static int add_indirect_ref(struct preftrees *preftrees, u64 root_id, | 365 | static int add_indirect_ref(const struct btrfs_fs_info *fs_info, |
366 | struct preftrees *preftrees, u64 root_id, | ||
373 | const struct btrfs_key *key, int level, | 367 | const struct btrfs_key *key, int level, |
374 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) | 368 | u64 wanted_disk_byte, int count, gfp_t gfp_mask) |
375 | { | 369 | { |
@@ -377,7 +371,7 @@ static int add_indirect_ref(struct preftrees *preftrees, u64 root_id, | |||
377 | 371 | ||
378 | if (!key) | 372 | if (!key) |
379 | tree = &preftrees->indirect_missing_keys; | 373 | tree = &preftrees->indirect_missing_keys; |
380 | return add_prelim_ref(tree, root_id, key, level, 0, | 374 | return add_prelim_ref(fs_info, tree, root_id, key, level, 0, |
381 | wanted_disk_byte, count, gfp_mask); | 375 | wanted_disk_byte, count, gfp_mask); |
382 | } | 376 | } |
383 | 377 | ||
@@ -631,7 +625,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
631 | * and return directly. | 625 | * and return directly. |
632 | */ | 626 | */ |
633 | if (err == -ENOENT) { | 627 | if (err == -ENOENT) { |
634 | prelim_ref_insert(&preftrees->direct, ref); | 628 | prelim_ref_insert(fs_info, &preftrees->direct, ref); |
635 | continue; | 629 | continue; |
636 | } else if (err) { | 630 | } else if (err) { |
637 | free_pref(ref); | 631 | free_pref(ref); |
@@ -659,11 +653,11 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
659 | memcpy(new_ref, ref, sizeof(*ref)); | 653 | memcpy(new_ref, ref, sizeof(*ref)); |
660 | new_ref->parent = node->val; | 654 | new_ref->parent = node->val; |
661 | new_ref->inode_list = unode_aux_to_inode_list(node); | 655 | new_ref->inode_list = unode_aux_to_inode_list(node); |
662 | prelim_ref_insert(&preftrees->direct, new_ref); | 656 | prelim_ref_insert(fs_info, &preftrees->direct, new_ref); |
663 | } | 657 | } |
664 | 658 | ||
665 | /* Now it's a direct ref, put it in the the direct tree */ | 659 | /* Now it's a direct ref, put it in the the direct tree */ |
666 | prelim_ref_insert(&preftrees->direct, ref); | 660 | prelim_ref_insert(fs_info, &preftrees->direct, ref); |
667 | 661 | ||
668 | ulist_reinit(parents); | 662 | ulist_reinit(parents); |
669 | } | 663 | } |
@@ -707,7 +701,7 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, | |||
707 | btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0); | 701 | btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0); |
708 | btrfs_tree_read_unlock(eb); | 702 | btrfs_tree_read_unlock(eb); |
709 | free_extent_buffer(eb); | 703 | free_extent_buffer(eb); |
710 | prelim_ref_insert(&preftrees->indirect, ref); | 704 | prelim_ref_insert(fs_info, &preftrees->indirect, ref); |
711 | } | 705 | } |
712 | return 0; | 706 | return 0; |
713 | } | 707 | } |
@@ -716,7 +710,8 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, | |||
716 | * add all currently queued delayed refs from this head whose seq nr is | 710 | * add all currently queued delayed refs from this head whose seq nr is |
717 | * smaller or equal that seq to the list | 711 | * smaller or equal that seq to the list |
718 | */ | 712 | */ |
719 | static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | 713 | static int add_delayed_refs(const struct btrfs_fs_info *fs_info, |
714 | struct btrfs_delayed_ref_head *head, u64 seq, | ||
720 | struct preftrees *preftrees, u64 *total_refs, | 715 | struct preftrees *preftrees, u64 *total_refs, |
721 | u64 inum) | 716 | u64 inum) |
722 | { | 717 | { |
@@ -759,8 +754,9 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
759 | struct btrfs_delayed_tree_ref *ref; | 754 | struct btrfs_delayed_tree_ref *ref; |
760 | 755 | ||
761 | ref = btrfs_delayed_node_to_tree_ref(node); | 756 | ref = btrfs_delayed_node_to_tree_ref(node); |
762 | ret = add_indirect_ref(preftrees, ref->root, &tmp_op_key, | 757 | ret = add_indirect_ref(fs_info, preftrees, ref->root, |
763 | ref->level + 1, node->bytenr, | 758 | &tmp_op_key, ref->level + 1, |
759 | node->bytenr, | ||
764 | node->ref_mod * sgn, | 760 | node->ref_mod * sgn, |
765 | GFP_ATOMIC); | 761 | GFP_ATOMIC); |
766 | break; | 762 | break; |
@@ -771,9 +767,9 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
771 | 767 | ||
772 | ref = btrfs_delayed_node_to_tree_ref(node); | 768 | ref = btrfs_delayed_node_to_tree_ref(node); |
773 | 769 | ||
774 | ret = add_direct_ref(preftrees, ref->level + 1, | 770 | ret = add_direct_ref(fs_info, preftrees, |
775 | ref->parent, node->bytenr, | 771 | ref->level + 1, ref->parent, |
776 | node->ref_mod * sgn, | 772 | node->bytenr, node->ref_mod * sgn, |
777 | GFP_ATOMIC); | 773 | GFP_ATOMIC); |
778 | break; | 774 | break; |
779 | } | 775 | } |
@@ -795,8 +791,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
795 | break; | 791 | break; |
796 | } | 792 | } |
797 | 793 | ||
798 | ret = add_indirect_ref(preftrees, ref->root, &key, 0, | 794 | ret = add_indirect_ref(fs_info, preftrees, ref->root, |
799 | node->bytenr, | 795 | &key, 0, node->bytenr, |
800 | node->ref_mod * sgn, | 796 | node->ref_mod * sgn, |
801 | GFP_ATOMIC); | 797 | GFP_ATOMIC); |
802 | break; | 798 | break; |
@@ -807,8 +803,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
807 | 803 | ||
808 | ref = btrfs_delayed_node_to_data_ref(node); | 804 | ref = btrfs_delayed_node_to_data_ref(node); |
809 | 805 | ||
810 | ret = add_direct_ref(preftrees, 0, ref->parent, | 806 | ret = add_direct_ref(fs_info, preftrees, 0, |
811 | node->bytenr, | 807 | ref->parent, node->bytenr, |
812 | node->ref_mod * sgn, | 808 | node->ref_mod * sgn, |
813 | GFP_ATOMIC); | 809 | GFP_ATOMIC); |
814 | break; | 810 | break; |
@@ -826,7 +822,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
826 | /* | 822 | /* |
827 | * add all inline backrefs for bytenr to the list | 823 | * add all inline backrefs for bytenr to the list |
828 | */ | 824 | */ |
829 | static int add_inline_refs(struct btrfs_path *path, u64 bytenr, | 825 | static int add_inline_refs(const struct btrfs_fs_info *fs_info, |
826 | struct btrfs_path *path, u64 bytenr, | ||
830 | int *info_level, struct preftrees *preftrees, | 827 | int *info_level, struct preftrees *preftrees, |
831 | u64 *total_refs, u64 inum) | 828 | u64 *total_refs, u64 inum) |
832 | { | 829 | { |
@@ -883,7 +880,8 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, | |||
883 | 880 | ||
884 | switch (type) { | 881 | switch (type) { |
885 | case BTRFS_SHARED_BLOCK_REF_KEY: | 882 | case BTRFS_SHARED_BLOCK_REF_KEY: |
886 | ret = add_direct_ref(preftrees, *info_level + 1, offset, | 883 | ret = add_direct_ref(fs_info, preftrees, |
884 | *info_level + 1, offset, | ||
887 | bytenr, 1, GFP_NOFS); | 885 | bytenr, 1, GFP_NOFS); |
888 | break; | 886 | break; |
889 | case BTRFS_SHARED_DATA_REF_KEY: { | 887 | case BTRFS_SHARED_DATA_REF_KEY: { |
@@ -893,14 +891,14 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, | |||
893 | sdref = (struct btrfs_shared_data_ref *)(iref + 1); | 891 | sdref = (struct btrfs_shared_data_ref *)(iref + 1); |
894 | count = btrfs_shared_data_ref_count(leaf, sdref); | 892 | count = btrfs_shared_data_ref_count(leaf, sdref); |
895 | 893 | ||
896 | ret = add_direct_ref(preftrees, 0, offset, | 894 | ret = add_direct_ref(fs_info, preftrees, 0, offset, |
897 | bytenr, count, GFP_NOFS); | 895 | bytenr, count, GFP_NOFS); |
898 | break; | 896 | break; |
899 | } | 897 | } |
900 | case BTRFS_TREE_BLOCK_REF_KEY: | 898 | case BTRFS_TREE_BLOCK_REF_KEY: |
901 | ret = add_indirect_ref(preftrees, offset, NULL, | 899 | ret = add_indirect_ref(fs_info, preftrees, offset, |
902 | *info_level + 1, bytenr, 1, | 900 | NULL, *info_level + 1, |
903 | GFP_NOFS); | 901 | bytenr, 1, GFP_NOFS); |
904 | break; | 902 | break; |
905 | case BTRFS_EXTENT_DATA_REF_KEY: { | 903 | case BTRFS_EXTENT_DATA_REF_KEY: { |
906 | struct btrfs_extent_data_ref *dref; | 904 | struct btrfs_extent_data_ref *dref; |
@@ -921,8 +919,9 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, | |||
921 | 919 | ||
922 | root = btrfs_extent_data_ref_root(leaf, dref); | 920 | root = btrfs_extent_data_ref_root(leaf, dref); |
923 | 921 | ||
924 | ret = add_indirect_ref(preftrees, root, &key, 0, bytenr, | 922 | ret = add_indirect_ref(fs_info, preftrees, root, |
925 | count, GFP_NOFS); | 923 | &key, 0, bytenr, count, |
924 | GFP_NOFS); | ||
926 | break; | 925 | break; |
927 | } | 926 | } |
928 | default: | 927 | default: |
@@ -973,9 +972,9 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
973 | switch (key.type) { | 972 | switch (key.type) { |
974 | case BTRFS_SHARED_BLOCK_REF_KEY: | 973 | case BTRFS_SHARED_BLOCK_REF_KEY: |
975 | /* SHARED DIRECT METADATA backref */ | 974 | /* SHARED DIRECT METADATA backref */ |
976 | ret = add_direct_ref(preftrees, info_level + 1, | 975 | ret = add_direct_ref(fs_info, preftrees, |
977 | key.offset, bytenr, 1, | 976 | info_level + 1, key.offset, |
978 | GFP_NOFS); | 977 | bytenr, 1, GFP_NOFS); |
979 | break; | 978 | break; |
980 | case BTRFS_SHARED_DATA_REF_KEY: { | 979 | case BTRFS_SHARED_DATA_REF_KEY: { |
981 | /* SHARED DIRECT FULL backref */ | 980 | /* SHARED DIRECT FULL backref */ |
@@ -985,15 +984,16 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
985 | sdref = btrfs_item_ptr(leaf, slot, | 984 | sdref = btrfs_item_ptr(leaf, slot, |
986 | struct btrfs_shared_data_ref); | 985 | struct btrfs_shared_data_ref); |
987 | count = btrfs_shared_data_ref_count(leaf, sdref); | 986 | count = btrfs_shared_data_ref_count(leaf, sdref); |
988 | ret = add_direct_ref(preftrees, 0, key.offset, bytenr, | 987 | ret = add_direct_ref(fs_info, preftrees, 0, |
989 | count, GFP_NOFS); | 988 | key.offset, bytenr, count, |
989 | GFP_NOFS); | ||
990 | break; | 990 | break; |
991 | } | 991 | } |
992 | case BTRFS_TREE_BLOCK_REF_KEY: | 992 | case BTRFS_TREE_BLOCK_REF_KEY: |
993 | /* NORMAL INDIRECT METADATA backref */ | 993 | /* NORMAL INDIRECT METADATA backref */ |
994 | ret = add_indirect_ref(preftrees, key.offset, NULL, | 994 | ret = add_indirect_ref(fs_info, preftrees, key.offset, |
995 | info_level + 1, bytenr, 1, | 995 | NULL, info_level + 1, bytenr, |
996 | GFP_NOFS); | 996 | 1, GFP_NOFS); |
997 | break; | 997 | break; |
998 | case BTRFS_EXTENT_DATA_REF_KEY: { | 998 | case BTRFS_EXTENT_DATA_REF_KEY: { |
999 | /* NORMAL INDIRECT DATA backref */ | 999 | /* NORMAL INDIRECT DATA backref */ |
@@ -1015,8 +1015,9 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
1015 | } | 1015 | } |
1016 | 1016 | ||
1017 | root = btrfs_extent_data_ref_root(leaf, dref); | 1017 | root = btrfs_extent_data_ref_root(leaf, dref); |
1018 | ret = add_indirect_ref(preftrees, root, &key, 0, bytenr, | 1018 | ret = add_indirect_ref(fs_info, preftrees, root, |
1019 | count, GFP_NOFS); | 1019 | &key, 0, bytenr, count, |
1020 | GFP_NOFS); | ||
1020 | break; | 1021 | break; |
1021 | } | 1022 | } |
1022 | default: | 1023 | default: |
@@ -1129,8 +1130,8 @@ again: | |||
1129 | goto again; | 1130 | goto again; |
1130 | } | 1131 | } |
1131 | spin_unlock(&delayed_refs->lock); | 1132 | spin_unlock(&delayed_refs->lock); |
1132 | ret = add_delayed_refs(head, time_seq, &preftrees, | 1133 | ret = add_delayed_refs(fs_info, head, time_seq, |
1133 | &total_refs, inum); | 1134 | &preftrees, &total_refs, inum); |
1134 | mutex_unlock(&head->mutex); | 1135 | mutex_unlock(&head->mutex); |
1135 | if (ret) | 1136 | if (ret) |
1136 | goto out; | 1137 | goto out; |
@@ -1150,8 +1151,9 @@ again: | |||
1150 | if (key.objectid == bytenr && | 1151 | if (key.objectid == bytenr && |
1151 | (key.type == BTRFS_EXTENT_ITEM_KEY || | 1152 | (key.type == BTRFS_EXTENT_ITEM_KEY || |
1152 | key.type == BTRFS_METADATA_ITEM_KEY)) { | 1153 | key.type == BTRFS_METADATA_ITEM_KEY)) { |
1153 | ret = add_inline_refs(path, bytenr, &info_level, | 1154 | ret = add_inline_refs(fs_info, path, bytenr, |
1154 | &preftrees, &total_refs, inum); | 1155 | &info_level, &preftrees, |
1156 | &total_refs, inum); | ||
1155 | if (ret) | 1157 | if (ret) |
1156 | goto out; | 1158 | goto out; |
1157 | ret = add_keyed_refs(fs_info, path, bytenr, info_level, | 1159 | ret = add_keyed_refs(fs_info, path, bytenr, info_level, |