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.c202
1 files changed, 126 insertions, 76 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 6290cf41d647..fe1ddbd2bfd6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -802,70 +802,57 @@ out:
802 return 0; 802 return 0;
803} 803}
804 804
805u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, 805
806 struct btrfs_path *count_path, 806static int get_reference_status(struct btrfs_root *root, u64 bytenr,
807 u64 expected_owner, 807 u64 parent_gen, u64 ref_objectid,
808 u64 first_extent) 808 u64 *min_generation, u32 *ref_count)
809{ 809{
810 struct btrfs_root *extent_root = root->fs_info->extent_root; 810 struct btrfs_root *extent_root = root->fs_info->extent_root;
811 struct btrfs_path *path; 811 struct btrfs_path *path;
812 u64 bytenr; 812 struct extent_buffer *leaf;
813 u64 found_objectid; 813 struct btrfs_extent_ref *ref_item;
814 u64 found_owner; 814 struct btrfs_key key;
815 struct btrfs_key found_key;
815 u64 root_objectid = root->root_key.objectid; 816 u64 root_objectid = root->root_key.objectid;
816 u32 total_count = 0; 817 u64 ref_generation;
817 u32 extent_refs;
818 u32 cur_count;
819 u32 nritems; 818 u32 nritems;
820 int ret; 819 int ret;
821 struct btrfs_key key;
822 struct btrfs_key found_key;
823 struct extent_buffer *l;
824 struct btrfs_extent_item *item;
825 struct btrfs_extent_ref *ref_item;
826 int level = -1;
827 820
828 /* FIXME, needs locking */
829 BUG();
830
831 mutex_lock(&root->fs_info->alloc_mutex);
832 path = btrfs_alloc_path();
833again:
834 if (level == -1)
835 bytenr = first_extent;
836 else
837 bytenr = count_path->nodes[level]->start;
838
839 cur_count = 0;
840 key.objectid = bytenr; 821 key.objectid = bytenr;
841 key.offset = 0; 822 key.offset = 0;
823 key.type = BTRFS_EXTENT_ITEM_KEY;
842 824
843 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 825 path = btrfs_alloc_path();
826 mutex_lock(&root->fs_info->alloc_mutex);
844 ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); 827 ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
845 if (ret < 0) 828 if (ret < 0)
846 goto out; 829 goto out;
847 BUG_ON(ret == 0); 830 BUG_ON(ret == 0);
848 831
849 l = path->nodes[0]; 832 leaf = path->nodes[0];
850 btrfs_item_key_to_cpu(l, &found_key, path->slots[0]); 833 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
851 834
852 if (found_key.objectid != bytenr || 835 if (found_key.objectid != bytenr ||
853 found_key.type != BTRFS_EXTENT_ITEM_KEY) { 836 found_key.type != BTRFS_EXTENT_ITEM_KEY) {
837 ret = 1;
854 goto out; 838 goto out;
855 } 839 }
856 840
857 item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); 841 *ref_count = 0;
858 extent_refs = btrfs_extent_refs(l, item); 842 *min_generation = (u64)-1;
843
859 while (1) { 844 while (1) {
860 l = path->nodes[0]; 845 leaf = path->nodes[0];
861 nritems = btrfs_header_nritems(l); 846 nritems = btrfs_header_nritems(leaf);
862 if (path->slots[0] >= nritems) { 847 if (path->slots[0] >= nritems) {
863 ret = btrfs_next_leaf(extent_root, path); 848 ret = btrfs_next_leaf(extent_root, path);
849 if (ret < 0)
850 goto out;
864 if (ret == 0) 851 if (ret == 0)
865 continue; 852 continue;
866 break; 853 break;
867 } 854 }
868 btrfs_item_key_to_cpu(l, &found_key, path->slots[0]); 855 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
869 if (found_key.objectid != bytenr) 856 if (found_key.objectid != bytenr)
870 break; 857 break;
871 858
@@ -874,57 +861,120 @@ again:
874 continue; 861 continue;
875 } 862 }
876 863
877 cur_count++; 864 ref_item = btrfs_item_ptr(leaf, path->slots[0],
878 ref_item = btrfs_item_ptr(l, path->slots[0],
879 struct btrfs_extent_ref); 865 struct btrfs_extent_ref);
880 found_objectid = btrfs_ref_root(l, ref_item); 866 ref_generation = btrfs_ref_generation(leaf, ref_item);
881 867 /*
882 if (found_objectid != root_objectid) { 868 * For (parent_gen > 0 && parent_gen > ref_gen):
883 total_count = 2; 869 *
884 goto out; 870 * we reach here through the oldest root, therefore
885 } 871 * all other reference from same snapshot should have
886 if (level == -1) { 872 * a larger generation.
887 found_owner = btrfs_ref_objectid(l, ref_item); 873 */
888 if (found_owner != expected_owner) { 874 if ((root_objectid != btrfs_ref_root(leaf, ref_item)) ||
889 total_count = 2; 875 (parent_gen > 0 && parent_gen > ref_generation) ||
890 goto out; 876 (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID &&
891 } 877 ref_objectid != btrfs_ref_objectid(leaf, ref_item))) {
892 /* 878 if (ref_count)
893 * nasty. we don't count a reference held by 879 *ref_count = 2;
894 * the running transaction. This allows nodatacow 880 break;
895 * to avoid cow most of the time
896 */
897 if (found_owner >= BTRFS_FIRST_FREE_OBJECTID &&
898 btrfs_ref_generation(l, ref_item) ==
899 root->fs_info->generation) {
900 extent_refs--;
901 }
902 } 881 }
903 total_count = 1; 882
883 *ref_count = 1;
884 if (*min_generation > ref_generation)
885 *min_generation = ref_generation;
886
904 path->slots[0]++; 887 path->slots[0]++;
905 } 888 }
906 /* 889 ret = 0;
907 * if there is more than one reference against a data extent, 890out:
908 * we have to assume the other ref is another snapshot 891 mutex_unlock(&root->fs_info->alloc_mutex);
909 */ 892 btrfs_free_path(path);
910 if (level == -1 && extent_refs > 1) { 893 return ret;
911 total_count = 2; 894}
895
896int btrfs_cross_ref_exists(struct btrfs_root *root,
897 struct btrfs_key *key, u64 bytenr)
898{
899 struct btrfs_trans_handle *trans;
900 struct btrfs_root *old_root;
901 struct btrfs_path *path = NULL;
902 struct extent_buffer *eb;
903 struct btrfs_file_extent_item *item;
904 u64 ref_generation;
905 u64 min_generation;
906 u64 extent_start;
907 u32 ref_count;
908 int level;
909 int ret;
910
911 BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY);
912 ret = get_reference_status(root, bytenr, 0, key->objectid,
913 &min_generation, &ref_count);
914 if (ret)
915 return ret;
916
917 if (ref_count != 1)
918 return 1;
919
920 trans = btrfs_start_transaction(root, 0);
921 old_root = root->dirty_root->root;
922 ref_generation = old_root->root_key.offset;
923
924 /* all references are created in running transaction */
925 if (min_generation > ref_generation) {
926 ret = 0;
912 goto out; 927 goto out;
913 } 928 }
914 if (cur_count == 0) { 929
915 total_count = 0; 930 path = btrfs_alloc_path();
931 if (!path) {
932 ret = -ENOMEM;
916 goto out; 933 goto out;
917 } 934 }
918 if (level >= 0 && root->node == count_path->nodes[level]) 935
936 path->skip_locking = 1;
937 /* if no item found, the extent is referenced by other snapshot */
938 ret = btrfs_search_slot(NULL, old_root, key, path, 0, 0);
939 if (ret)
919 goto out; 940 goto out;
920 level++;
921 btrfs_release_path(root, path);
922 goto again;
923 941
942 eb = path->nodes[0];
943 item = btrfs_item_ptr(eb, path->slots[0],
944 struct btrfs_file_extent_item);
945 if (btrfs_file_extent_type(eb, item) != BTRFS_FILE_EXTENT_REG ||
946 btrfs_file_extent_disk_bytenr(eb, item) != bytenr) {
947 ret = 1;
948 goto out;
949 }
950
951 for (level = BTRFS_MAX_LEVEL - 1; level >= -1; level--) {
952 if (level >= 0) {
953 eb = path->nodes[level];
954 if (!eb)
955 continue;
956 extent_start = eb->start;
957 } else
958 extent_start = bytenr;
959
960 ret = get_reference_status(root, extent_start, ref_generation,
961 0, &min_generation, &ref_count);
962 if (ret)
963 goto out;
964
965 if (ref_count != 1) {
966 ret = 1;
967 goto out;
968 }
969 if (level >= 0)
970 ref_generation = btrfs_header_generation(eb);
971 }
972 ret = 0;
924out: 973out:
925 btrfs_free_path(path); 974 if (path)
926 mutex_unlock(&root->fs_info->alloc_mutex); 975 btrfs_free_path(path);
927 return total_count; 976 btrfs_end_transaction(trans, root);
977 return ret;
928} 978}
929 979
930int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 980int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,