aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-07-30 09:26:11 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitf321e4910398cf7922265d269fb17fd26f312571 (patch)
tree8430f004991351e48a4b3f9441fe0cbbcf70eddb /fs/btrfs/extent-tree.c
parent3bf10418675cb424724b5cb9d7725b234defe1fd (diff)
Btrfs: Update and fix mount -o nodatacow
To check whether a given file extent is referenced by multiple snapshots, the checker walks down the fs tree through dead root and checks all tree blocks in the path. We can easily detect whether a given tree block is directly referenced by other snapshot. We can also detect any indirect reference from other snapshot by checking reference's generation. The checker can always detect multiple references, but can't reliably detect cases of single reference. So btrfs may do file data cow even there is only one reference. Signed-off-by: Chris Mason <chris.mason@oracle.com>
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,