diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-02-22 11:39:13 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-02-22 11:39:13 -0500 |
commit | 5c680ed620c2b69cf751aecf1a5e03ce2c89c7f3 (patch) | |
tree | 53777ed1d7a37c8c619893a81fc68a9de07e5990 /fs/btrfs/ctree.c | |
parent | cfaa72952fa7b44aa5d967cbc266110900552aef (diff) |
Btrfs: switch to early splits
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 263 |
1 files changed, 118 insertions, 145 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 2891b582e26f..1b4e82d8074d 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -5,7 +5,12 @@ | |||
5 | #include "ctree.h" | 5 | #include "ctree.h" |
6 | #include "disk-io.h" | 6 | #include "disk-io.h" |
7 | 7 | ||
8 | #define SEARCH_READ 0 | ||
9 | #define SEARCH_WRITE 1 | ||
10 | |||
8 | static int refill_alloc_extent(struct ctree_root *root); | 11 | static int refill_alloc_extent(struct ctree_root *root); |
12 | 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); | ||
9 | 14 | ||
10 | static inline void init_path(struct ctree_path *p) | 15 | static inline void init_path(struct ctree_path *p) |
11 | { | 16 | { |
@@ -125,14 +130,14 @@ int bin_search(struct node *c, struct key *key, int *slot) | |||
125 | * If the key isn't found, the path points to the slot where it should | 130 | * If the key isn't found, the path points to the slot where it should |
126 | * be inserted. | 131 | * be inserted. |
127 | */ | 132 | */ |
128 | int search_slot(struct ctree_root *root, struct key *key, struct ctree_path *p) | 133 | int search_slot(struct ctree_root *root, struct key *key, struct ctree_path *p, int ins_len) |
129 | { | 134 | { |
130 | struct tree_buffer *b = root->node; | 135 | struct tree_buffer *b = root->node; |
131 | struct node *c; | 136 | struct node *c; |
132 | |||
133 | int slot; | 137 | int slot; |
134 | int ret; | 138 | int ret; |
135 | int level; | 139 | int level; |
140 | |||
136 | b->count++; | 141 | b->count++; |
137 | while (b) { | 142 | while (b) { |
138 | c = &b->node; | 143 | c = &b->node; |
@@ -143,10 +148,26 @@ int search_slot(struct ctree_root *root, struct key *key, struct ctree_path *p) | |||
143 | if (ret && slot > 0) | 148 | if (ret && slot > 0) |
144 | slot -= 1; | 149 | slot -= 1; |
145 | p->slots[level] = slot; | 150 | p->slots[level] = slot; |
151 | if (ins_len && c->header.nritems == NODEPTRS_PER_BLOCK) { | ||
152 | int sret = split_node(root, p, level); | ||
153 | BUG_ON(sret > 0); | ||
154 | if (sret) | ||
155 | return sret; | ||
156 | b = p->nodes[level]; | ||
157 | c = &b->node; | ||
158 | slot = p->slots[level]; | ||
159 | } | ||
146 | b = read_tree_block(root, c->blockptrs[slot]); | 160 | b = read_tree_block(root, c->blockptrs[slot]); |
147 | continue; | 161 | continue; |
148 | } else { | 162 | } else { |
163 | struct leaf *l = (struct leaf *)c; | ||
149 | p->slots[level] = slot; | 164 | p->slots[level] = slot; |
165 | if (ins_len && leaf_free_space(l) < sizeof(struct item) + ins_len) { | ||
166 | int sret = split_leaf(root, p, ins_len); | ||
167 | BUG_ON(sret > 0); | ||
168 | if (sret) | ||
169 | return sret; | ||
170 | } | ||
150 | return ret; | 171 | return ret; |
151 | } | 172 | } |
152 | } | 173 | } |
@@ -331,50 +352,54 @@ int push_node_right(struct ctree_root *root, struct ctree_path *path, int level) | |||
331 | return 0; | 352 | return 0; |
332 | } | 353 | } |
333 | 354 | ||
355 | static int insert_new_root(struct ctree_root *root, struct ctree_path *path, int level) | ||
356 | { | ||
357 | struct tree_buffer *t; | ||
358 | struct node *lower; | ||
359 | struct node *c; | ||
360 | struct key *lower_key; | ||
361 | |||
362 | BUG_ON(path->nodes[level]); | ||
363 | BUG_ON(path->nodes[level-1] != root->node); | ||
364 | |||
365 | t = alloc_free_block(root); | ||
366 | c = &t->node; | ||
367 | memset(c, 0, sizeof(c)); | ||
368 | c->header.nritems = 1; | ||
369 | c->header.flags = node_level(level); | ||
370 | c->header.blocknr = t->blocknr; | ||
371 | c->header.parentid = root->node->node.header.parentid; | ||
372 | lower = &path->nodes[level-1]->node; | ||
373 | if (is_leaf(lower->header.flags)) | ||
374 | lower_key = &((struct leaf *)lower)->items[0].key; | ||
375 | else | ||
376 | lower_key = lower->keys; | ||
377 | memcpy(c->keys, lower_key, sizeof(struct key)); | ||
378 | c->blockptrs[0] = path->nodes[level-1]->blocknr; | ||
379 | /* the super has an extra ref to root->node */ | ||
380 | tree_block_release(root, root->node); | ||
381 | root->node = t; | ||
382 | t->count++; | ||
383 | write_tree_block(root, t); | ||
384 | path->nodes[level] = t; | ||
385 | path->slots[level] = 0; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
334 | /* | 389 | /* |
335 | * worker function to insert a single pointer in a node. | 390 | * worker function to insert a single pointer in a node. |
336 | * the node should have enough room for the pointer already | 391 | * the node should have enough room for the pointer already |
337 | * slot and level indicate where you want the key to go, and | 392 | * slot and level indicate where you want the key to go, and |
338 | * blocknr is the block the key points to. | 393 | * blocknr is the block the key points to. |
339 | */ | 394 | */ |
340 | int __insert_ptr(struct ctree_root *root, | 395 | int insert_ptr(struct ctree_root *root, |
341 | struct ctree_path *path, struct key *key, | 396 | struct ctree_path *path, struct key *key, |
342 | u64 blocknr, int slot, int level) | 397 | u64 blocknr, int slot, int level) |
343 | { | 398 | { |
344 | struct node *c; | ||
345 | struct node *lower; | 399 | struct node *lower; |
346 | struct key *lower_key; | ||
347 | int nritems; | 400 | int nritems; |
348 | /* need a new root */ | 401 | |
349 | if (!path->nodes[level]) { | 402 | BUG_ON(!path->nodes[level]); |
350 | struct tree_buffer *t; | ||
351 | t = alloc_free_block(root); | ||
352 | c = &t->node; | ||
353 | memset(c, 0, sizeof(c)); | ||
354 | c->header.nritems = 2; | ||
355 | c->header.flags = node_level(level); | ||
356 | c->header.blocknr = t->blocknr; | ||
357 | c->header.parentid = root->node->node.header.parentid; | ||
358 | lower = &path->nodes[level-1]->node; | ||
359 | if (is_leaf(lower->header.flags)) | ||
360 | lower_key = &((struct leaf *)lower)->items[0].key; | ||
361 | else | ||
362 | lower_key = lower->keys; | ||
363 | memcpy(c->keys, lower_key, sizeof(struct key)); | ||
364 | memcpy(c->keys + 1, key, sizeof(struct key)); | ||
365 | c->blockptrs[0] = path->nodes[level-1]->blocknr; | ||
366 | c->blockptrs[1] = blocknr; | ||
367 | /* the super has an extra ref to root->node */ | ||
368 | tree_block_release(root, root->node); | ||
369 | root->node = t; | ||
370 | t->count++; | ||
371 | write_tree_block(root, t); | ||
372 | path->nodes[level] = t; | ||
373 | path->slots[level] = 0; | ||
374 | if (c->keys[1].objectid == 0) | ||
375 | BUG(); | ||
376 | return 0; | ||
377 | } | ||
378 | lower = &path->nodes[level]->node; | 403 | lower = &path->nodes[level]->node; |
379 | nritems = lower->header.nritems; | 404 | nritems = lower->header.nritems; |
380 | if (slot > nritems) | 405 | if (slot > nritems) |
@@ -396,93 +421,54 @@ int __insert_ptr(struct ctree_root *root, | |||
396 | return 0; | 421 | return 0; |
397 | } | 422 | } |
398 | 423 | ||
399 | 424 | int split_node(struct ctree_root *root, struct ctree_path *path, int level) | |
400 | /* | ||
401 | * insert a key,blocknr pair into the tree at a given level | ||
402 | * If the node at that level in the path doesn't have room, | ||
403 | * it is split or shifted as appropriate. | ||
404 | */ | ||
405 | int insert_ptr(struct ctree_root *root, | ||
406 | struct ctree_path *path, struct key *key, | ||
407 | u64 blocknr, int level) | ||
408 | { | 425 | { |
409 | struct tree_buffer *t = path->nodes[level]; | 426 | struct tree_buffer *t; |
410 | struct node *c = &path->nodes[level]->node; | 427 | struct node *c; |
411 | struct node *b; | 428 | struct tree_buffer *split_buffer; |
412 | struct tree_buffer *b_buffer; | 429 | struct node *split; |
413 | struct tree_buffer *bal[MAX_LEVEL]; | ||
414 | int bal_level = level; | ||
415 | int mid; | 430 | int mid; |
416 | int bal_start = -1; | 431 | int ret; |
417 | |||
418 | /* | ||
419 | * check to see if we need to make room in the node for this | ||
420 | * pointer. If we do, keep walking the tree, making sure there | ||
421 | * is enough room in each level for the required insertions. | ||
422 | * | ||
423 | * The bal array is filled in with any nodes to be inserted | ||
424 | * due to splitting. Once we've done all the splitting required | ||
425 | * do the inserts based on the data in the bal array. | ||
426 | */ | ||
427 | memset(bal, 0, sizeof(bal)); | ||
428 | while(t && t->node.header.nritems == NODEPTRS_PER_BLOCK) { | ||
429 | c = &t->node; | ||
430 | if (push_node_left(root, path, | ||
431 | node_level(c->header.flags)) == 0) | ||
432 | break; | ||
433 | if (push_node_right(root, path, | ||
434 | node_level(c->header.flags)) == 0) | ||
435 | break; | ||
436 | bal_start = bal_level; | ||
437 | if (bal_level == MAX_LEVEL - 1) | ||
438 | BUG(); | ||
439 | b_buffer = alloc_free_block(root); | ||
440 | b = &b_buffer->node; | ||
441 | b->header.flags = c->header.flags; | ||
442 | b->header.blocknr = b_buffer->blocknr; | ||
443 | b->header.parentid = root->node->node.header.parentid; | ||
444 | mid = (c->header.nritems + 1) / 2; | ||
445 | memcpy(b->keys, c->keys + mid, | ||
446 | (c->header.nritems - mid) * sizeof(struct key)); | ||
447 | memcpy(b->blockptrs, c->blockptrs + mid, | ||
448 | (c->header.nritems - mid) * sizeof(u64)); | ||
449 | b->header.nritems = c->header.nritems - mid; | ||
450 | c->header.nritems = mid; | ||
451 | |||
452 | write_tree_block(root, t); | ||
453 | write_tree_block(root, b_buffer); | ||
454 | 432 | ||
455 | bal[bal_level] = b_buffer; | 433 | ret = push_node_left(root, path, level); |
456 | if (bal_level == MAX_LEVEL - 1) | 434 | if (!ret) |
457 | break; | 435 | return 0; |
458 | bal_level += 1; | 436 | ret = push_node_right(root, path, level); |
459 | t = path->nodes[bal_level]; | 437 | if (!ret) |
438 | return 0; | ||
439 | t = path->nodes[level]; | ||
440 | c = &t->node; | ||
441 | if (t == root->node) { | ||
442 | /* trying to split the root, lets make a new one */ | ||
443 | ret = insert_new_root(root, path, level + 1); | ||
444 | if (ret) | ||
445 | return ret; | ||
460 | } | 446 | } |
461 | /* | 447 | split_buffer = alloc_free_block(root); |
462 | * bal_start tells us the first level in the tree that needed to | 448 | split = &split_buffer->node; |
463 | * be split. Go through the bal array inserting the new nodes | 449 | split->header.flags = c->header.flags; |
464 | * as needed. The path is fixed as we go. | 450 | split->header.blocknr = split_buffer->blocknr; |
465 | */ | 451 | split->header.parentid = root->node->node.header.parentid; |
466 | while(bal_start > 0) { | 452 | mid = (c->header.nritems + 1) / 2; |
467 | b_buffer = bal[bal_start]; | 453 | memcpy(split->keys, c->keys + mid, |
468 | c = &path->nodes[bal_start]->node; | 454 | (c->header.nritems - mid) * sizeof(struct key)); |
469 | __insert_ptr(root, path, b_buffer->node.keys, b_buffer->blocknr, | 455 | memcpy(split->blockptrs, c->blockptrs + mid, |
470 | path->slots[bal_start + 1] + 1, bal_start + 1); | 456 | (c->header.nritems - mid) * sizeof(u64)); |
471 | if (path->slots[bal_start] >= c->header.nritems) { | 457 | split->header.nritems = c->header.nritems - mid; |
472 | path->slots[bal_start] -= c->header.nritems; | 458 | c->header.nritems = mid; |
473 | tree_block_release(root, path->nodes[bal_start]); | 459 | write_tree_block(root, t); |
474 | path->nodes[bal_start] = b_buffer; | 460 | write_tree_block(root, split_buffer); |
475 | path->slots[bal_start + 1] += 1; | 461 | insert_ptr(root, path, split->keys, split_buffer->blocknr, |
476 | } else { | 462 | path->slots[level + 1] + 1, level + 1); |
477 | tree_block_release(root, b_buffer); | 463 | if (path->slots[level] > mid) { |
478 | } | 464 | path->slots[level] -= mid; |
479 | bal_start--; | 465 | tree_block_release(root, t); |
480 | if (!bal[bal_start]) | 466 | path->nodes[level] = split_buffer; |
481 | break; | 467 | path->slots[level + 1] += 1; |
468 | } else { | ||
469 | tree_block_release(root, split_buffer); | ||
482 | } | 470 | } |
483 | /* Now that the tree has room, insert the requested pointer */ | 471 | return 0; |
484 | return __insert_ptr(root, path, key, blocknr, path->slots[level] + 1, | ||
485 | level); | ||
486 | } | 472 | } |
487 | 473 | ||
488 | /* | 474 | /* |
@@ -623,6 +609,11 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
623 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) | 609 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) |
624 | return 0; | 610 | return 0; |
625 | } | 611 | } |
612 | if (!path->nodes[1]) { | ||
613 | ret = insert_new_root(root, path, 1); | ||
614 | if (ret) | ||
615 | return ret; | ||
616 | } | ||
626 | slot = path->slots[0]; | 617 | slot = path->slots[0]; |
627 | nritems = l->header.nritems; | 618 | nritems = l->header.nritems; |
628 | mid = (nritems + 1)/ 2; | 619 | mid = (nritems + 1)/ 2; |
@@ -659,8 +650,7 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
659 | 650 | ||
660 | l->header.nritems = mid; | 651 | l->header.nritems = mid; |
661 | ret = insert_ptr(root, path, &right->items[0].key, | 652 | ret = insert_ptr(root, path, &right->items[0].key, |
662 | right_buffer->blocknr, 1); | 653 | right_buffer->blocknr, path->slots[1] + 1, 1); |
663 | |||
664 | write_tree_block(root, right_buffer); | 654 | write_tree_block(root, right_buffer); |
665 | write_tree_block(root, l_buf); | 655 | write_tree_block(root, l_buf); |
666 | 656 | ||
@@ -695,21 +685,10 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
695 | refill_alloc_extent(root); | 685 | refill_alloc_extent(root); |
696 | 686 | ||
697 | /* create a root if there isn't one */ | 687 | /* create a root if there isn't one */ |
698 | if (!root->node) { | 688 | if (!root->node) |
699 | BUG(); | 689 | BUG(); |
700 | #if 0 | ||
701 | struct tree_buffer *t; | ||
702 | t = alloc_free_block(root); | ||
703 | BUG_ON(!t); | ||
704 | t->node.header.nritems = 0; | ||
705 | t->node.header.flags = node_level(0); | ||
706 | t->node.header.blocknr = t->blocknr; | ||
707 | root->node = t; | ||
708 | write_tree_block(root, t); | ||
709 | #endif | ||
710 | } | ||
711 | init_path(&path); | 690 | init_path(&path); |
712 | ret = search_slot(root, key, &path); | 691 | ret = search_slot(root, key, &path, data_size); |
713 | if (ret == 0) { | 692 | if (ret == 0) { |
714 | release_path(root, &path); | 693 | release_path(root, &path); |
715 | return -EEXIST; | 694 | return -EEXIST; |
@@ -719,12 +698,6 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
719 | leaf_buf = path.nodes[0]; | 698 | leaf_buf = path.nodes[0]; |
720 | leaf = &leaf_buf->leaf; | 699 | leaf = &leaf_buf->leaf; |
721 | 700 | ||
722 | /* make room if needed */ | ||
723 | if (leaf_free_space(leaf) < sizeof(struct item) + data_size) { | ||
724 | split_leaf(root, &path, data_size); | ||
725 | leaf_buf = path.nodes[0]; | ||
726 | leaf = &path.nodes[0]->leaf; | ||
727 | } | ||
728 | nritems = leaf->header.nritems; | 701 | nritems = leaf->header.nritems; |
729 | data_end = leaf_data_end(leaf); | 702 | data_end = leaf_data_end(leaf); |
730 | 703 | ||
@@ -950,7 +923,7 @@ int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, | |||
950 | ins->offset = 0; | 923 | ins->offset = 0; |
951 | ins->flags = 0; | 924 | ins->flags = 0; |
952 | 925 | ||
953 | ret = search_slot(root, ins, &path); | 926 | ret = search_slot(root, ins, &path, sizeof(struct extent_item)); |
954 | while (1) { | 927 | while (1) { |
955 | l = &path.nodes[0]->leaf; | 928 | l = &path.nodes[0]->leaf; |
956 | slot = path.slots[0]; | 929 | slot = path.slots[0]; |
@@ -1097,8 +1070,8 @@ void print_tree(struct ctree_root *root, struct tree_buffer *t) | |||
1097 | 1070 | ||
1098 | /* for testing only */ | 1071 | /* for testing only */ |
1099 | int next_key(int i, int max_key) { | 1072 | int next_key(int i, int max_key) { |
1100 | return rand() % max_key; | 1073 | // return rand() % max_key; |
1101 | // return i; | 1074 | return i; |
1102 | } | 1075 | } |
1103 | 1076 | ||
1104 | int main() { | 1077 | int main() { |
@@ -1154,7 +1127,7 @@ int main() { | |||
1154 | num = next_key(i, max_key); | 1127 | num = next_key(i, max_key); |
1155 | ins.objectid = num; | 1128 | ins.objectid = num; |
1156 | init_path(&path); | 1129 | init_path(&path); |
1157 | ret = search_slot(root, &ins, &path); | 1130 | ret = search_slot(root, &ins, &path, 0); |
1158 | if (ret) { | 1131 | if (ret) { |
1159 | print_tree(root, root->node); | 1132 | print_tree(root, root->node); |
1160 | printf("unable to find %d\n", num); | 1133 | printf("unable to find %d\n", num); |
@@ -1176,7 +1149,7 @@ int main() { | |||
1176 | num = next_key(i, max_key); | 1149 | num = next_key(i, max_key); |
1177 | ins.objectid = num; | 1150 | ins.objectid = num; |
1178 | init_path(&path); | 1151 | init_path(&path); |
1179 | ret = search_slot(root, &ins, &path); | 1152 | ret = search_slot(root, &ins, &path, 0); |
1180 | if (ret) | 1153 | if (ret) |
1181 | continue; | 1154 | continue; |
1182 | ret = del_item(root, &path); | 1155 | ret = del_item(root, &path); |
@@ -1204,7 +1177,7 @@ int main() { | |||
1204 | num = next_key(i, max_key); | 1177 | num = next_key(i, max_key); |
1205 | ins.objectid = num; | 1178 | ins.objectid = num; |
1206 | init_path(&path); | 1179 | init_path(&path); |
1207 | ret = search_slot(root, &ins, &path); | 1180 | ret = search_slot(root, &ins, &path, 0); |
1208 | if (ret) { | 1181 | if (ret) { |
1209 | print_tree(root, root->node); | 1182 | print_tree(root, root->node); |
1210 | printf("unable to find %d\n", num); | 1183 | printf("unable to find %d\n", num); |
@@ -1218,7 +1191,7 @@ int main() { | |||
1218 | int slot; | 1191 | int slot; |
1219 | ins.objectid = (u64)-1; | 1192 | ins.objectid = (u64)-1; |
1220 | init_path(&path); | 1193 | init_path(&path); |
1221 | ret = search_slot(root, &ins, &path); | 1194 | ret = search_slot(root, &ins, &path, 0); |
1222 | if (ret == 0) | 1195 | if (ret == 0) |
1223 | BUG(); | 1196 | BUG(); |
1224 | 1197 | ||