aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c131
1 files changed, 18 insertions, 113 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 535cee47fcfb..1eb69a91b727 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -848,9 +848,8 @@ out:
848 return 0; 848 return 0;
849} 849}
850 850
851static int get_reference_status(struct btrfs_root *root, u64 bytenr, 851int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
852 u64 parent_gen, u64 ref_objectid, 852 struct btrfs_root *root, u64 bytenr)
853 u64 *min_generation, u32 *ref_count)
854{ 853{
855 struct btrfs_root *extent_root = root->fs_info->extent_root; 854 struct btrfs_root *extent_root = root->fs_info->extent_root;
856 struct btrfs_path *path; 855 struct btrfs_path *path;
@@ -858,8 +857,8 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
858 struct btrfs_extent_ref *ref_item; 857 struct btrfs_extent_ref *ref_item;
859 struct btrfs_key key; 858 struct btrfs_key key;
860 struct btrfs_key found_key; 859 struct btrfs_key found_key;
861 u64 root_objectid = root->root_key.objectid; 860 u64 ref_root;
862 u64 ref_generation; 861 u64 last_snapshot;
863 u32 nritems; 862 u32 nritems;
864 int ret; 863 int ret;
865 864
@@ -872,7 +871,9 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
872 if (ret < 0) 871 if (ret < 0)
873 goto out; 872 goto out;
874 BUG_ON(ret == 0); 873 BUG_ON(ret == 0);
875 if (ret < 0 || path->slots[0] == 0) 874
875 ret = -ENOENT;
876 if (path->slots[0] == 0)
876 goto out; 877 goto out;
877 878
878 path->slots[0]--; 879 path->slots[0]--;
@@ -880,14 +881,10 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
880 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 881 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
881 882
882 if (found_key.objectid != bytenr || 883 if (found_key.objectid != bytenr ||
883 found_key.type != BTRFS_EXTENT_ITEM_KEY) { 884 found_key.type != BTRFS_EXTENT_ITEM_KEY)
884 ret = 1;
885 goto out; 885 goto out;
886 }
887
888 *ref_count = 0;
889 *min_generation = (u64)-1;
890 886
887 last_snapshot = btrfs_root_last_snapshot(&root->root_item);
891 while (1) { 888 while (1) {
892 leaf = path->nodes[0]; 889 leaf = path->nodes[0];
893 nritems = btrfs_header_nritems(leaf); 890 nritems = btrfs_header_nritems(leaf);
@@ -910,114 +907,22 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
910 907
911 ref_item = btrfs_item_ptr(leaf, path->slots[0], 908 ref_item = btrfs_item_ptr(leaf, path->slots[0],
912 struct btrfs_extent_ref); 909 struct btrfs_extent_ref);
913 ref_generation = btrfs_ref_generation(leaf, ref_item); 910 ref_root = btrfs_ref_root(leaf, ref_item);
914 /* 911 if (ref_root != root->root_key.objectid &&
915 * For (parent_gen > 0 && parent_gen > ref_generation): 912 ref_root != BTRFS_TREE_LOG_OBJECTID) {
916 * 913 ret = 1;
917 * we reach here through the oldest root, therefore
918 * all other reference from same snapshot should have
919 * a larger generation.
920 */
921 if ((root_objectid != btrfs_ref_root(leaf, ref_item)) ||
922 (parent_gen > 0 && parent_gen > ref_generation) ||
923 (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID &&
924 ref_objectid != btrfs_ref_objectid(leaf, ref_item))) {
925 *ref_count = 2;
926 break;
927 }
928
929 *ref_count = 1;
930 if (*min_generation > ref_generation)
931 *min_generation = ref_generation;
932
933 path->slots[0]++;
934 }
935 ret = 0;
936out:
937 btrfs_free_path(path);
938 return ret;
939}
940
941int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
942 struct btrfs_root *root,
943 struct btrfs_key *key, u64 bytenr)
944{
945 struct btrfs_root *old_root;
946 struct btrfs_path *path = NULL;
947 struct extent_buffer *eb;
948 struct btrfs_file_extent_item *item;
949 u64 ref_generation;
950 u64 min_generation;
951 u64 extent_start;
952 u32 ref_count;
953 int level;
954 int ret;
955
956 BUG_ON(trans == NULL);
957 BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY);
958 ret = get_reference_status(root, bytenr, 0, key->objectid,
959 &min_generation, &ref_count);
960 if (ret)
961 return ret;
962
963 if (ref_count != 1)
964 return 1;
965
966 old_root = root->dirty_root->root;
967 ref_generation = old_root->root_key.offset;
968
969 /* all references are created in running transaction */
970 if (min_generation > ref_generation) {
971 ret = 0;
972 goto out;
973 }
974
975 path = btrfs_alloc_path();
976 if (!path) {
977 ret = -ENOMEM;
978 goto out;
979 }
980
981 path->skip_locking = 1;
982 /* if no item found, the extent is referenced by other snapshot */
983 ret = btrfs_search_slot(NULL, old_root, key, path, 0, 0);
984 if (ret)
985 goto out;
986
987 eb = path->nodes[0];
988 item = btrfs_item_ptr(eb, path->slots[0],
989 struct btrfs_file_extent_item);
990 if (btrfs_file_extent_type(eb, item) != BTRFS_FILE_EXTENT_REG ||
991 btrfs_file_extent_disk_bytenr(eb, item) != bytenr) {
992 ret = 1;
993 goto out;
994 }
995
996 for (level = BTRFS_MAX_LEVEL - 1; level >= -1; level--) {
997 if (level >= 0) {
998 eb = path->nodes[level];
999 if (!eb)
1000 continue;
1001 extent_start = eb->start;
1002 } else
1003 extent_start = bytenr;
1004
1005 ret = get_reference_status(root, extent_start, ref_generation,
1006 0, &min_generation, &ref_count);
1007 if (ret)
1008 goto out; 914 goto out;
1009 915 }
1010 if (ref_count != 1) { 916 if (btrfs_ref_generation(leaf, ref_item) <= last_snapshot) {
1011 ret = 1; 917 ret = 1;
1012 goto out; 918 goto out;
1013 } 919 }
1014 if (level >= 0) 920
1015 ref_generation = btrfs_header_generation(eb); 921 path->slots[0]++;
1016 } 922 }
1017 ret = 0; 923 ret = 0;
1018out: 924out:
1019 if (path) 925 btrfs_free_path(path);
1020 btrfs_free_path(path);
1021 return ret; 926 return ret;
1022} 927}
1023 928