diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-04 14:08:15 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-04 14:08:15 -0400 |
commit | d4dbff953e1f6f4079126c0404cc24f2ef14e925 (patch) | |
tree | 293d3fbe74ce991dbd1dc07ef4b9a97ff0337546 /fs/btrfs/ctree.c | |
parent | df24a2b9c9bcef3348e4b1a8f206cd484a248d36 (diff) |
Btrfs: support for items bigger than 1/2 the blocksize
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 132 |
1 files changed, 97 insertions, 35 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9ef65e2ecf51..864ee423b300 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -6,7 +6,8 @@ | |||
6 | static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | 6 | static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root |
7 | *root, struct btrfs_path *path, int level); | 7 | *root, struct btrfs_path *path, int level); |
8 | static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | 8 | static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root |
9 | *root, struct btrfs_path *path, int data_size); | 9 | *root, struct btrfs_key *ins_key, |
10 | struct btrfs_path *path, int data_size); | ||
10 | static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root | 11 | static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root |
11 | *root, struct buffer_head *dst, struct buffer_head | 12 | *root, struct buffer_head *dst, struct buffer_head |
12 | *src); | 13 | *src); |
@@ -102,19 +103,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root, | |||
102 | } | 103 | } |
103 | 104 | ||
104 | /* | 105 | /* |
105 | * The space between the end of the leaf items and | ||
106 | * the start of the leaf data. IOW, how much room | ||
107 | * the leaf has left for both items and data | ||
108 | */ | ||
109 | int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf) | ||
110 | { | ||
111 | int data_end = leaf_data_end(root, leaf); | ||
112 | int nritems = btrfs_header_nritems(&leaf->header); | ||
113 | char *items_end = (char *)(leaf->items + nritems + 1); | ||
114 | return (char *)(btrfs_leaf_data(leaf) + data_end) - (char *)items_end; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * compare two keys in a memcmp fashion | 106 | * compare two keys in a memcmp fashion |
119 | */ | 107 | */ |
120 | static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) | 108 | static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) |
@@ -510,8 +498,8 @@ again: | |||
510 | if (ret && slot > 0) | 498 | if (ret && slot > 0) |
511 | slot -= 1; | 499 | slot -= 1; |
512 | p->slots[level] = slot; | 500 | p->slots[level] = slot; |
513 | if (ins_len > 0 && btrfs_header_nritems(&c->header) == | 501 | if (ins_len > 0 && btrfs_header_nritems(&c->header) >= |
514 | BTRFS_NODEPTRS_PER_BLOCK(root)) { | 502 | BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { |
515 | int sret = split_node(trans, root, p, level); | 503 | int sret = split_node(trans, root, p, level); |
516 | BUG_ON(sret > 0); | 504 | BUG_ON(sret > 0); |
517 | if (sret) | 505 | if (sret) |
@@ -537,7 +525,8 @@ again: | |||
537 | p->slots[level] = slot; | 525 | p->slots[level] = slot; |
538 | if (ins_len > 0 && btrfs_leaf_free_space(root, l) < | 526 | if (ins_len > 0 && btrfs_leaf_free_space(root, l) < |
539 | sizeof(struct btrfs_item) + ins_len) { | 527 | sizeof(struct btrfs_item) + ins_len) { |
540 | int sret = split_leaf(trans, root, p, ins_len); | 528 | int sret = split_leaf(trans, root, key, |
529 | p, ins_len); | ||
541 | BUG_ON(sret > 0); | 530 | BUG_ON(sret > 0); |
542 | if (sret) | 531 | if (sret) |
543 | return sret; | 532 | return sret; |
@@ -825,17 +814,30 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | |||
825 | static int leaf_space_used(struct btrfs_leaf *l, int start, int nr) | 814 | static int leaf_space_used(struct btrfs_leaf *l, int start, int nr) |
826 | { | 815 | { |
827 | int data_len; | 816 | int data_len; |
828 | int end = start + nr - 1; | 817 | int nritems = btrfs_header_nritems(&l->header); |
818 | int end = min(nritems, start + nr) - 1; | ||
829 | 819 | ||
830 | if (!nr) | 820 | if (!nr) |
831 | return 0; | 821 | return 0; |
832 | data_len = btrfs_item_end(l->items + start); | 822 | data_len = btrfs_item_end(l->items + start); |
833 | data_len = data_len - btrfs_item_offset(l->items + end); | 823 | data_len = data_len - btrfs_item_offset(l->items + end); |
834 | data_len += sizeof(struct btrfs_item) * nr; | 824 | data_len += sizeof(struct btrfs_item) * nr; |
825 | WARN_ON(data_len < 0); | ||
835 | return data_len; | 826 | return data_len; |
836 | } | 827 | } |
837 | 828 | ||
838 | /* | 829 | /* |
830 | * The space between the end of the leaf items and | ||
831 | * the start of the leaf data. IOW, how much room | ||
832 | * the leaf has left for both items and data | ||
833 | */ | ||
834 | int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf) | ||
835 | { | ||
836 | int nritems = btrfs_header_nritems(&leaf->header); | ||
837 | return BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems); | ||
838 | } | ||
839 | |||
840 | /* | ||
839 | * push some data in the path leaf to the right, trying to free up at | 841 | * push some data in the path leaf to the right, trying to free up at |
840 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 842 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
841 | * | 843 | * |
@@ -1084,7 +1086,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1084 | * returns 0 if all went well and < 0 on failure. | 1086 | * returns 0 if all went well and < 0 on failure. |
1085 | */ | 1087 | */ |
1086 | static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | 1088 | static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root |
1087 | *root, struct btrfs_path *path, int data_size) | 1089 | *root, struct btrfs_key *ins_key, |
1090 | struct btrfs_path *path, int data_size) | ||
1088 | { | 1091 | { |
1089 | struct buffer_head *l_buf; | 1092 | struct buffer_head *l_buf; |
1090 | struct btrfs_leaf *l; | 1093 | struct btrfs_leaf *l; |
@@ -1097,8 +1100,10 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1097 | int data_copy_size; | 1100 | int data_copy_size; |
1098 | int rt_data_off; | 1101 | int rt_data_off; |
1099 | int i; | 1102 | int i; |
1100 | int ret; | 1103 | int ret = 0; |
1101 | int wret; | 1104 | int wret; |
1105 | int double_split = 0; | ||
1106 | struct btrfs_disk_key disk_key; | ||
1102 | 1107 | ||
1103 | /* first try to make some room by pushing left and right */ | 1108 | /* first try to make some room by pushing left and right */ |
1104 | wret = push_leaf_left(trans, root, path, data_size); | 1109 | wret = push_leaf_left(trans, root, path, data_size); |
@@ -1127,26 +1132,58 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1127 | mid = (nritems + 1)/ 2; | 1132 | mid = (nritems + 1)/ 2; |
1128 | right_buffer = btrfs_alloc_free_block(trans, root); | 1133 | right_buffer = btrfs_alloc_free_block(trans, root); |
1129 | BUG_ON(!right_buffer); | 1134 | BUG_ON(!right_buffer); |
1130 | BUG_ON(mid == nritems); | ||
1131 | right = btrfs_buffer_leaf(right_buffer); | 1135 | right = btrfs_buffer_leaf(right_buffer); |
1132 | memset(&right->header, 0, sizeof(right->header)); | 1136 | memset(&right->header, 0, sizeof(right->header)); |
1133 | if (mid <= slot) { | ||
1134 | /* FIXME, just alloc a new leaf here */ | ||
1135 | if (leaf_space_used(l, mid, nritems - mid) + space_needed > | ||
1136 | BTRFS_LEAF_DATA_SIZE(root)) | ||
1137 | BUG(); | ||
1138 | } else { | ||
1139 | /* FIXME, just alloc a new leaf here */ | ||
1140 | if (leaf_space_used(l, 0, mid + 1) + space_needed > | ||
1141 | BTRFS_LEAF_DATA_SIZE(root)) | ||
1142 | BUG(); | ||
1143 | } | ||
1144 | btrfs_set_header_nritems(&right->header, nritems - mid); | ||
1145 | btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); | 1137 | btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); |
1146 | btrfs_set_header_generation(&right->header, trans->transid); | 1138 | btrfs_set_header_generation(&right->header, trans->transid); |
1147 | btrfs_set_header_level(&right->header, 0); | 1139 | btrfs_set_header_level(&right->header, 0); |
1148 | btrfs_set_header_parentid(&right->header, | 1140 | btrfs_set_header_parentid(&right->header, |
1149 | btrfs_header_parentid(btrfs_buffer_header(root->node))); | 1141 | btrfs_header_parentid(btrfs_buffer_header(root->node))); |
1142 | if (mid <= slot) { | ||
1143 | if (nritems == 1 || | ||
1144 | leaf_space_used(l, mid, nritems - mid) + space_needed > | ||
1145 | BTRFS_LEAF_DATA_SIZE(root)) { | ||
1146 | if (slot >= nritems) { | ||
1147 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | ||
1148 | btrfs_set_header_nritems(&right->header, 0); | ||
1149 | wret = insert_ptr(trans, root, path, | ||
1150 | &disk_key, | ||
1151 | right_buffer->b_blocknr, | ||
1152 | path->slots[1] + 1, 1); | ||
1153 | if (wret) | ||
1154 | ret = wret; | ||
1155 | btrfs_block_release(root, path->nodes[0]); | ||
1156 | path->nodes[0] = right_buffer; | ||
1157 | path->slots[0] = 0; | ||
1158 | path->slots[1] += 1; | ||
1159 | return ret; | ||
1160 | } | ||
1161 | mid = slot; | ||
1162 | double_split = 1; | ||
1163 | } | ||
1164 | } else { | ||
1165 | if (leaf_space_used(l, 0, mid + 1) + space_needed > | ||
1166 | BTRFS_LEAF_DATA_SIZE(root)) { | ||
1167 | if (slot == 0) { | ||
1168 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | ||
1169 | btrfs_set_header_nritems(&right->header, 0); | ||
1170 | wret = insert_ptr(trans, root, path, | ||
1171 | &disk_key, | ||
1172 | right_buffer->b_blocknr, | ||
1173 | path->slots[1] - 1, 1); | ||
1174 | if (wret) | ||
1175 | ret = wret; | ||
1176 | btrfs_block_release(root, path->nodes[0]); | ||
1177 | path->nodes[0] = right_buffer; | ||
1178 | path->slots[0] = 0; | ||
1179 | path->slots[1] -= 1; | ||
1180 | return ret; | ||
1181 | } | ||
1182 | mid = slot; | ||
1183 | double_split = 1; | ||
1184 | } | ||
1185 | } | ||
1186 | btrfs_set_header_nritems(&right->header, nritems - mid); | ||
1150 | data_copy_size = btrfs_item_end(l->items + mid) - | 1187 | data_copy_size = btrfs_item_end(l->items + mid) - |
1151 | leaf_data_end(root, l); | 1188 | leaf_data_end(root, l); |
1152 | btrfs_memcpy(root, right, right->items, l->items + mid, | 1189 | btrfs_memcpy(root, right, right->items, l->items + mid, |
@@ -1180,6 +1217,31 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1180 | } else | 1217 | } else |
1181 | btrfs_block_release(root, right_buffer); | 1218 | btrfs_block_release(root, right_buffer); |
1182 | BUG_ON(path->slots[0] < 0); | 1219 | BUG_ON(path->slots[0] < 0); |
1220 | |||
1221 | if (!double_split) | ||
1222 | return ret; | ||
1223 | right_buffer = btrfs_alloc_free_block(trans, root); | ||
1224 | BUG_ON(!right_buffer); | ||
1225 | right = btrfs_buffer_leaf(right_buffer); | ||
1226 | memset(&right->header, 0, sizeof(right->header)); | ||
1227 | btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); | ||
1228 | btrfs_set_header_generation(&right->header, trans->transid); | ||
1229 | btrfs_set_header_level(&right->header, 0); | ||
1230 | btrfs_set_header_parentid(&right->header, | ||
1231 | btrfs_header_parentid(btrfs_buffer_header(root->node))); | ||
1232 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | ||
1233 | btrfs_set_header_nritems(&right->header, 0); | ||
1234 | wret = insert_ptr(trans, root, path, | ||
1235 | &disk_key, | ||
1236 | right_buffer->b_blocknr, | ||
1237 | path->slots[1], 1); | ||
1238 | if (wret) | ||
1239 | ret = wret; | ||
1240 | btrfs_block_release(root, path->nodes[0]); | ||
1241 | path->nodes[0] = right_buffer; | ||
1242 | path->slots[0] = 0; | ||
1243 | check_node(root, path, 1); | ||
1244 | check_leaf(root, path, 0); | ||
1183 | return ret; | 1245 | return ret; |
1184 | } | 1246 | } |
1185 | 1247 | ||
@@ -1220,9 +1282,9 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1220 | data_end = leaf_data_end(root, leaf); | 1282 | data_end = leaf_data_end(root, leaf); |
1221 | 1283 | ||
1222 | if (btrfs_leaf_free_space(root, leaf) < | 1284 | if (btrfs_leaf_free_space(root, leaf) < |
1223 | sizeof(struct btrfs_item) + data_size) | 1285 | sizeof(struct btrfs_item) + data_size) { |
1224 | BUG(); | 1286 | BUG(); |
1225 | 1287 | } | |
1226 | slot = path->slots[0]; | 1288 | slot = path->slots[0]; |
1227 | BUG_ON(slot < 0); | 1289 | BUG_ON(slot < 0); |
1228 | if (slot != nritems) { | 1290 | if (slot != nritems) { |