diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 131 |
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 | ||
851 | static int get_reference_status(struct btrfs_root *root, u64 bytenr, | 851 | int 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; | ||
936 | out: | ||
937 | btrfs_free_path(path); | ||
938 | return ret; | ||
939 | } | ||
940 | |||
941 | int 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; |
1018 | out: | 924 | out: |
1019 | if (path) | 925 | btrfs_free_path(path); |
1020 | btrfs_free_path(path); | ||
1021 | return ret; | 926 | return ret; |
1022 | } | 927 | } |
1023 | 928 | ||