diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-02-23 08:38:36 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-02-23 08:38:36 -0500 |
commit | 9a8dd1502de6aa683ae46cf0397e9b6e636416fb (patch) | |
tree | 2422c1c316fe97014d8972431dbbe3f91a28853a /fs/btrfs/ctree.c | |
parent | 5c680ed620c2b69cf751aecf1a5e03ce2c89c7f3 (diff) |
Btrfs: Block sized tree extents and extent deletion
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 245 |
1 files changed, 198 insertions, 47 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 1b4e82d8074d..f0abcf1f3939 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -8,9 +8,12 @@ | |||
8 | #define SEARCH_READ 0 | 8 | #define SEARCH_READ 0 |
9 | #define SEARCH_WRITE 1 | 9 | #define SEARCH_WRITE 1 |
10 | 10 | ||
11 | static int refill_alloc_extent(struct ctree_root *root); | 11 | #define CTREE_EXTENT_PENDING 0 |
12 | |||
12 | int split_node(struct ctree_root *root, struct ctree_path *path, int level); | 13 | int split_node(struct ctree_root *root, struct ctree_path *path, int level); |
13 | int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size); | 14 | int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size); |
15 | struct tree_buffer *alloc_free_block(struct ctree_root *root); | ||
16 | int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks); | ||
14 | 17 | ||
15 | static inline void init_path(struct ctree_path *p) | 18 | static inline void init_path(struct ctree_path *p) |
16 | { | 19 | { |
@@ -682,8 +685,6 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
682 | unsigned int data_end; | 685 | unsigned int data_end; |
683 | struct ctree_path path; | 686 | struct ctree_path path; |
684 | 687 | ||
685 | refill_alloc_extent(root); | ||
686 | |||
687 | /* create a root if there isn't one */ | 688 | /* create a root if there isn't one */ |
688 | if (!root->node) | 689 | if (!root->node) |
689 | BUG(); | 690 | BUG(); |
@@ -756,6 +757,7 @@ int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | |||
756 | struct tree_buffer *t; | 757 | struct tree_buffer *t; |
757 | struct node *node; | 758 | struct node *node; |
758 | int nritems; | 759 | int nritems; |
760 | u64 blocknr; | ||
759 | 761 | ||
760 | while(1) { | 762 | while(1) { |
761 | t = path->nodes[level]; | 763 | t = path->nodes[level]; |
@@ -774,6 +776,7 @@ int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | |||
774 | } | 776 | } |
775 | node->header.nritems--; | 777 | node->header.nritems--; |
776 | write_tree_block(root, t); | 778 | write_tree_block(root, t); |
779 | blocknr = t->blocknr; | ||
777 | if (node->header.nritems != 0) { | 780 | if (node->header.nritems != 0) { |
778 | int tslot; | 781 | int tslot; |
779 | if (slot == 0) | 782 | if (slot == 0) |
@@ -799,6 +802,7 @@ int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | |||
799 | break; | 802 | break; |
800 | } | 803 | } |
801 | level++; | 804 | level++; |
805 | free_extent(root, blocknr, 1); | ||
802 | if (!path->nodes[level]) | 806 | if (!path->nodes[level]) |
803 | BUG(); | 807 | BUG(); |
804 | } | 808 | } |
@@ -841,8 +845,10 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
841 | if (leaf_buf == root->node) { | 845 | if (leaf_buf == root->node) { |
842 | leaf->header.flags = node_level(0); | 846 | leaf->header.flags = node_level(0); |
843 | write_tree_block(root, leaf_buf); | 847 | write_tree_block(root, leaf_buf); |
844 | } else | 848 | } else { |
845 | del_ptr(root, path, 1); | 849 | del_ptr(root, path, 1); |
850 | free_extent(root, leaf_buf->blocknr, 1); | ||
851 | } | ||
846 | } else { | 852 | } else { |
847 | if (slot == 0) | 853 | if (slot == 0) |
848 | fixup_low_keys(root, path, &leaf->items[0].key, 1); | 854 | fixup_low_keys(root, path, &leaf->items[0].key, 1); |
@@ -867,6 +873,72 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
867 | return 0; | 873 | return 0; |
868 | } | 874 | } |
869 | 875 | ||
876 | static int del_pending_extents(struct ctree_root *extent_root) | ||
877 | { | ||
878 | int ret; | ||
879 | struct key key; | ||
880 | struct tree_buffer *gang[4]; | ||
881 | int i; | ||
882 | struct ctree_path path; | ||
883 | |||
884 | while(1) { | ||
885 | ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix, | ||
886 | (void **)gang, 0, ARRAY_SIZE(gang), | ||
887 | CTREE_EXTENT_PENDING); | ||
888 | if (!ret) | ||
889 | break; | ||
890 | for (i = 0; i < ret; i++) { | ||
891 | key.objectid = gang[i]->blocknr; | ||
892 | key.flags = 0; | ||
893 | key.offset = 1; | ||
894 | init_path(&path); | ||
895 | ret = search_slot(extent_root, &key, &path, 0); | ||
896 | if (ret) { | ||
897 | BUG(); | ||
898 | // FIXME undo it and return sane | ||
899 | return ret; | ||
900 | } | ||
901 | ret = del_item(extent_root, &path); | ||
902 | if (ret) { | ||
903 | BUG(); | ||
904 | return ret; | ||
905 | } | ||
906 | release_path(extent_root, &path); | ||
907 | radix_tree_tag_clear(&extent_root->cache_radix, gang[i]->blocknr, | ||
908 | CTREE_EXTENT_PENDING); | ||
909 | tree_block_release(extent_root, gang[i]); | ||
910 | } | ||
911 | } | ||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks) | ||
916 | { | ||
917 | struct ctree_path path; | ||
918 | struct key key; | ||
919 | struct ctree_root *extent_root = root->extent_root; | ||
920 | struct tree_buffer *t; | ||
921 | int pending_ret; | ||
922 | int ret; | ||
923 | |||
924 | key.objectid = blocknr; | ||
925 | key.flags = 0; | ||
926 | key.offset = num_blocks; | ||
927 | if (root == extent_root) { | ||
928 | t = read_tree_block(root, key.objectid); | ||
929 | radix_tree_tag_set(&root->cache_radix, key.objectid, CTREE_EXTENT_PENDING); | ||
930 | return 0; | ||
931 | } | ||
932 | init_path(&path); | ||
933 | ret = search_slot(extent_root, &key, &path, 0); | ||
934 | if (ret) | ||
935 | BUG(); | ||
936 | ret = del_item(extent_root, &path); | ||
937 | release_path(extent_root, &path); | ||
938 | pending_ret = del_pending_extents(root->extent_root); | ||
939 | return ret ? ret : pending_ret; | ||
940 | } | ||
941 | |||
870 | int next_leaf(struct ctree_root *root, struct ctree_path *path) | 942 | int next_leaf(struct ctree_root *root, struct ctree_path *path) |
871 | { | 943 | { |
872 | int slot; | 944 | int slot; |
@@ -904,8 +976,8 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) | |||
904 | return 0; | 976 | return 0; |
905 | } | 977 | } |
906 | 978 | ||
907 | int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, | 979 | int find_free_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, |
908 | u64 search_end, u64 owner, struct key *ins) | 980 | u64 search_end, struct key *ins) |
909 | { | 981 | { |
910 | struct ctree_path path; | 982 | struct ctree_path path; |
911 | struct key *key; | 983 | struct key *key; |
@@ -915,15 +987,13 @@ int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, | |||
915 | u64 last_block; | 987 | u64 last_block; |
916 | int start_found = 0; | 988 | int start_found = 0; |
917 | struct leaf *l; | 989 | struct leaf *l; |
918 | struct extent_item extent_item; | ||
919 | struct ctree_root * root = orig_root->extent_root; | 990 | struct ctree_root * root = orig_root->extent_root; |
920 | 991 | ||
921 | init_path(&path); | 992 | init_path(&path); |
922 | ins->objectid = search_start; | 993 | ins->objectid = search_start; |
923 | ins->offset = 0; | 994 | ins->offset = 0; |
924 | ins->flags = 0; | 995 | ins->flags = 0; |
925 | 996 | ret = search_slot(root, ins, &path, 0); | |
926 | ret = search_slot(root, ins, &path, sizeof(struct extent_item)); | ||
927 | while (1) { | 997 | while (1) { |
928 | l = &path.nodes[0]->leaf; | 998 | l = &path.nodes[0]->leaf; |
929 | slot = path.slots[0]; | 999 | slot = path.slots[0]; |
@@ -938,6 +1008,7 @@ int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, | |||
938 | ins->objectid = search_start; | 1008 | ins->objectid = search_start; |
939 | ins->offset = num_blocks; | 1009 | ins->offset = num_blocks; |
940 | hole_size = search_end - search_start; | 1010 | hole_size = search_end - search_start; |
1011 | start_found = 1; | ||
941 | goto insert; | 1012 | goto insert; |
942 | } | 1013 | } |
943 | ins->objectid = last_block; | 1014 | ins->objectid = last_block; |
@@ -956,51 +1027,119 @@ int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, | |||
956 | } else | 1027 | } else |
957 | start_found = 1; | 1028 | start_found = 1; |
958 | last_block = key->objectid + key->offset; | 1029 | last_block = key->objectid + key->offset; |
1030 | insert_failed: | ||
959 | path.slots[0]++; | 1031 | path.slots[0]++; |
960 | } | 1032 | } |
961 | // FIXME -ENOSPC | 1033 | // FIXME -ENOSPC |
962 | insert: | 1034 | insert: |
1035 | if (orig_root->extent_root == orig_root) { | ||
1036 | BUG_ON(num_blocks != 1); | ||
1037 | if ((root->current_insert.objectid <= ins->objectid && | ||
1038 | root->current_insert.objectid + root->current_insert.offset > | ||
1039 | ins->objectid) || | ||
1040 | (root->current_insert.objectid > ins->objectid && | ||
1041 | root->current_insert.objectid <= ins->objectid + ins->offset) || | ||
1042 | radix_tree_tag_get(&root->cache_radix, ins->objectid, | ||
1043 | CTREE_EXTENT_PENDING)) { | ||
1044 | last_block = ins->objectid + 1; | ||
1045 | search_start = last_block; | ||
1046 | goto insert_failed; | ||
1047 | } | ||
1048 | } | ||
963 | release_path(root, &path); | 1049 | release_path(root, &path); |
1050 | if (ins->offset != 1) | ||
1051 | BUG(); | ||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
1055 | static int insert_pending_extents(struct ctree_root *extent_root) | ||
1056 | { | ||
1057 | int ret; | ||
1058 | struct key key; | ||
1059 | struct extent_item item; | ||
1060 | struct tree_buffer *gang[4]; | ||
1061 | int i; | ||
1062 | |||
1063 | // FIXME -ENOSPC | ||
1064 | item.refs = 1; | ||
1065 | item.owner = extent_root->node->node.header.parentid; | ||
1066 | while(1) { | ||
1067 | ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix, | ||
1068 | (void **)gang, 0, ARRAY_SIZE(gang), | ||
1069 | CTREE_EXTENT_PENDING); | ||
1070 | if (!ret) | ||
1071 | break; | ||
1072 | for (i = 0; i < ret; i++) { | ||
1073 | key.objectid = gang[i]->blocknr; | ||
1074 | key.flags = 0; | ||
1075 | key.offset = 1; | ||
1076 | ret = insert_item(extent_root, &key, &item, sizeof(item)); | ||
1077 | if (ret) { | ||
1078 | BUG(); | ||
1079 | // FIXME undo it and return sane | ||
1080 | return ret; | ||
1081 | } | ||
1082 | radix_tree_tag_clear(&extent_root->cache_radix, gang[i]->blocknr, | ||
1083 | CTREE_EXTENT_PENDING); | ||
1084 | tree_block_release(extent_root, gang[i]); | ||
1085 | } | ||
1086 | } | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, | ||
1091 | u64 search_end, u64 owner, struct key *ins, struct tree_buffer **buf) | ||
1092 | { | ||
1093 | int ret; | ||
1094 | int pending_ret; | ||
1095 | struct extent_item extent_item; | ||
1096 | |||
964 | extent_item.refs = 1; | 1097 | extent_item.refs = 1; |
965 | extent_item.owner = owner; | 1098 | extent_item.owner = owner; |
966 | if (root == orig_root && root->reserve_extent->num_blocks == 0) { | 1099 | |
967 | root->reserve_extent->blocknr = ins->objectid; | 1100 | ret = find_free_extent(root, num_blocks, search_start, search_end, ins); |
968 | root->reserve_extent->num_blocks = ins->offset; | 1101 | if (ret) |
969 | root->reserve_extent->num_used = 0; | 1102 | return ret; |
1103 | |||
1104 | if (root != root->extent_root) { | ||
1105 | memcpy(&root->extent_root->current_insert, ins, sizeof(*ins)); | ||
1106 | ret = insert_item(root->extent_root, ins, &extent_item, sizeof(extent_item)); | ||
1107 | memset(&root->extent_root->current_insert, 0, sizeof(struct key)); | ||
1108 | pending_ret = insert_pending_extents(root->extent_root); | ||
1109 | if (ret) | ||
1110 | return ret; | ||
1111 | if (pending_ret) | ||
1112 | return pending_ret; | ||
1113 | *buf = find_tree_block(root, ins->objectid); | ||
1114 | return 0; | ||
970 | } | 1115 | } |
971 | ret = insert_item(root->extent_root, ins, &extent_item, sizeof(extent_item)); | 1116 | /* we're allocating an extent for the extent tree, don't recurse */ |
972 | return ret; | 1117 | BUG_ON(ins->offset != 1); |
1118 | *buf = find_tree_block(root, ins->objectid); | ||
1119 | BUG_ON(!*buf); | ||
1120 | radix_tree_tag_set(&root->cache_radix, ins->objectid, CTREE_EXTENT_PENDING); | ||
1121 | (*buf)->count++; | ||
1122 | return 0; | ||
1123 | |||
973 | } | 1124 | } |
974 | 1125 | ||
975 | static int refill_alloc_extent(struct ctree_root *root) | 1126 | struct tree_buffer *alloc_free_block(struct ctree_root *root) |
976 | { | 1127 | { |
977 | struct alloc_extent *ae = root->alloc_extent; | 1128 | struct key ins; |
978 | struct key key; | ||
979 | int ret; | 1129 | int ret; |
980 | int min_blocks = MAX_LEVEL * 2; | 1130 | struct tree_buffer *buf = NULL; |
981 | 1131 | ||
982 | if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used > | 1132 | ret = alloc_extent(root, 1, 0, (unsigned long)-1, root->node->node.header.parentid, |
983 | min_blocks) | 1133 | &ins, &buf); |
984 | return 0; | 1134 | |
985 | ae = root->reserve_extent; | 1135 | if (ret) { |
986 | if (ae->num_blocks > ae->num_used) { | 1136 | BUG(); |
987 | if (root->alloc_extent->num_blocks == 0) { | 1137 | return NULL; |
988 | /* we should swap reserve/alloc_extent when alloc | ||
989 | * fills up | ||
990 | */ | ||
991 | BUG(); | ||
992 | } | ||
993 | if (ae->num_blocks - ae->num_used < min_blocks) | ||
994 | BUG(); | ||
995 | return 0; | ||
996 | } | 1138 | } |
997 | ret = alloc_extent(root, | 1139 | if (root != root->extent_root) |
998 | min_blocks * 2, 0, (unsigned long)-1, | 1140 | BUG_ON(radix_tree_tag_get(&root->extent_root->cache_radix, buf->blocknr, |
999 | root->node->node.header.parentid, &key); | 1141 | CTREE_EXTENT_PENDING)); |
1000 | ae->blocknr = key.objectid; | 1142 | return buf; |
1001 | ae->num_blocks = key.offset; | ||
1002 | ae->num_used = 0; | ||
1003 | return ret; | ||
1004 | } | 1143 | } |
1005 | 1144 | ||
1006 | void print_leaf(struct leaf *l) | 1145 | void print_leaf(struct leaf *l) |
@@ -1096,6 +1235,7 @@ int main() { | |||
1096 | print_tree(root, root->node); | 1235 | print_tree(root, root->node); |
1097 | printf("map tree\n"); | 1236 | printf("map tree\n"); |
1098 | print_tree(root->extent_root, root->extent_root->node); | 1237 | print_tree(root->extent_root, root->extent_root->node); |
1238 | fflush(stdout); | ||
1099 | 1239 | ||
1100 | srand(55); | 1240 | srand(55); |
1101 | for (i = 0; i < run_size; i++) { | 1241 | for (i = 0; i < run_size; i++) { |
@@ -1111,12 +1251,6 @@ int main() { | |||
1111 | if (!ret) | 1251 | if (!ret) |
1112 | tree_size++; | 1252 | tree_size++; |
1113 | } | 1253 | } |
1114 | printf("root used: %lu\n", root->alloc_extent->num_used); | ||
1115 | printf("root tree\n"); | ||
1116 | // print_tree(root, root->node); | ||
1117 | printf("map tree\n"); | ||
1118 | printf("map used: %lu\n", root->extent_root->alloc_extent->num_used); | ||
1119 | // print_tree(root->extent_root, root->extent_root->node); | ||
1120 | write_ctree_super(root, &super); | 1254 | write_ctree_super(root, &super); |
1121 | close_ctree(root); | 1255 | close_ctree(root); |
1122 | 1256 | ||
@@ -1167,12 +1301,27 @@ int main() { | |||
1167 | ret = insert_item(root, &ins, buf, strlen(buf)); | 1301 | ret = insert_item(root, &ins, buf, strlen(buf)); |
1168 | if (!ret) | 1302 | if (!ret) |
1169 | tree_size++; | 1303 | tree_size++; |
1304 | if (i >= 5) { | ||
1305 | struct key ugh; | ||
1306 | ugh.objectid = 5; | ||
1307 | ugh.flags = 0; | ||
1308 | ugh.offset = 0; | ||
1309 | init_path(&path); | ||
1310 | ret = search_slot(root, &ugh, &path, 0); | ||
1311 | if (ret) { | ||
1312 | print_tree(root, root->node); | ||
1313 | printf("unable to find 5 %d\n", num); | ||
1314 | exit(1); | ||
1315 | } | ||
1316 | release_path(root, &path); | ||
1317 | |||
1318 | } | ||
1170 | } | 1319 | } |
1171 | write_ctree_super(root, &super); | 1320 | write_ctree_super(root, &super); |
1172 | close_ctree(root); | 1321 | close_ctree(root); |
1173 | root = open_ctree("dbfile", &super); | 1322 | root = open_ctree("dbfile", &super); |
1174 | printf("starting search2\n"); | ||
1175 | srand(128); | 1323 | srand(128); |
1324 | printf("starting search2\n"); | ||
1176 | for (i = 0; i < run_size; i++) { | 1325 | for (i = 0; i < run_size; i++) { |
1177 | num = next_key(i, max_key); | 1326 | num = next_key(i, max_key); |
1178 | ins.objectid = num; | 1327 | ins.objectid = num; |
@@ -1219,5 +1368,7 @@ int main() { | |||
1219 | write_ctree_super(root, &super); | 1368 | write_ctree_super(root, &super); |
1220 | close_ctree(root); | 1369 | close_ctree(root); |
1221 | printf("tree size is now %d\n", tree_size); | 1370 | printf("tree size is now %d\n", tree_size); |
1371 | printf("map tree\n"); | ||
1372 | print_tree(root->extent_root, root->extent_root->node); | ||
1222 | return 0; | 1373 | return 0; |
1223 | } | 1374 | } |