diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-02-28 16:35:06 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-02-28 16:35:06 -0500 |
commit | aa5d6bed255d7f8c655a8f10d760f4247bc8385c (patch) | |
tree | ddd4ad69b490fc49e23097f5d783ef90ea81cf5f /fs/btrfs/ctree.c | |
parent | af86d07efe83e2f2da3658702a720bc48b1a6d78 (diff) |
Btrfs: return code checking
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 480 |
1 files changed, 254 insertions, 226 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0aea94224ba3..be2be0272513 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -6,12 +6,15 @@ | |||
6 | #include "disk-io.h" | 6 | #include "disk-io.h" |
7 | #include "print-tree.h" | 7 | #include "print-tree.h" |
8 | 8 | ||
9 | int split_node(struct ctree_root *root, struct ctree_path *path, int level); | 9 | static int split_node(struct ctree_root *root, struct ctree_path *path, |
10 | int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size); | 10 | int level); |
11 | int push_node_left(struct ctree_root *root, struct ctree_path *path, int level); | 11 | static int split_leaf(struct ctree_root *root, struct ctree_path *path, |
12 | int push_node_right(struct ctree_root *root, | 12 | int data_size); |
13 | static int push_node_left(struct ctree_root *root, struct ctree_path *path, | ||
14 | int level); | ||
15 | static int push_node_right(struct ctree_root *root, | ||
13 | struct ctree_path *path, int level); | 16 | struct ctree_path *path, int level); |
14 | int del_ptr(struct ctree_root *root, struct ctree_path *path, int level); | 17 | static int del_ptr(struct ctree_root *root, struct ctree_path *path, int level); |
15 | 18 | ||
16 | inline void init_path(struct ctree_path *p) | 19 | inline void init_path(struct ctree_path *p) |
17 | { | 20 | { |
@@ -26,6 +29,7 @@ void release_path(struct ctree_root *root, struct ctree_path *p) | |||
26 | break; | 29 | break; |
27 | tree_block_release(root, p->nodes[i]); | 30 | tree_block_release(root, p->nodes[i]); |
28 | } | 31 | } |
32 | memset(p, 0, sizeof(*p)); | ||
29 | } | 33 | } |
30 | 34 | ||
31 | /* | 35 | /* |
@@ -74,6 +78,67 @@ int comp_keys(struct key *k1, struct key *k2) | |||
74 | return 0; | 78 | return 0; |
75 | } | 79 | } |
76 | 80 | ||
81 | int check_node(struct ctree_path *path, int level) | ||
82 | { | ||
83 | int i; | ||
84 | struct node *parent = NULL; | ||
85 | struct node *node = &path->nodes[level]->node; | ||
86 | int parent_slot; | ||
87 | |||
88 | if (path->nodes[level + 1]) | ||
89 | parent = &path->nodes[level + 1]->node; | ||
90 | parent_slot = path->slots[level + 1]; | ||
91 | if (parent && node->header.nritems > 0) { | ||
92 | struct key *parent_key; | ||
93 | parent_key = &parent->keys[parent_slot]; | ||
94 | BUG_ON(memcmp(parent_key, node->keys, sizeof(struct key))); | ||
95 | BUG_ON(parent->blockptrs[parent_slot] != node->header.blocknr); | ||
96 | } | ||
97 | BUG_ON(node->header.nritems > NODEPTRS_PER_BLOCK); | ||
98 | for (i = 0; i < node->header.nritems - 2; i++) { | ||
99 | BUG_ON(comp_keys(&node->keys[i], &node->keys[i+1]) >= 0); | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | int check_leaf(struct ctree_path *path, int level) | ||
105 | { | ||
106 | int i; | ||
107 | struct leaf *leaf = &path->nodes[level]->leaf; | ||
108 | struct node *parent = NULL; | ||
109 | int parent_slot; | ||
110 | |||
111 | if (path->nodes[level + 1]) | ||
112 | parent = &path->nodes[level + 1]->node; | ||
113 | parent_slot = path->slots[level + 1]; | ||
114 | if (parent && leaf->header.nritems > 0) { | ||
115 | struct key *parent_key; | ||
116 | parent_key = &parent->keys[parent_slot]; | ||
117 | BUG_ON(memcmp(parent_key, &leaf->items[0].key, | ||
118 | sizeof(struct key))); | ||
119 | BUG_ON(parent->blockptrs[parent_slot] != leaf->header.blocknr); | ||
120 | } | ||
121 | for (i = 0; i < leaf->header.nritems - 2; i++) { | ||
122 | BUG_ON(comp_keys(&leaf->items[i].key, | ||
123 | &leaf->items[i+1].key) >= 0); | ||
124 | BUG_ON(leaf->items[i].offset != leaf->items[i + 1].offset + | ||
125 | leaf->items[i + 1].size); | ||
126 | if (i == 0) { | ||
127 | BUG_ON(leaf->items[i].offset + leaf->items[i].size != | ||
128 | LEAF_DATA_SIZE); | ||
129 | } | ||
130 | } | ||
131 | BUG_ON(leaf_free_space(leaf) < 0); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | int check_block(struct ctree_path *path, int level) | ||
136 | { | ||
137 | if (level == 0) | ||
138 | return check_leaf(path, level); | ||
139 | return check_node(path, level); | ||
140 | } | ||
141 | |||
77 | /* | 142 | /* |
78 | * search for key in the array p. items p are item_size apart | 143 | * search for key in the array p. items p are item_size apart |
79 | * and there are 'max' items in p | 144 | * and there are 'max' items in p |
@@ -133,7 +198,8 @@ int bin_search(struct node *c, struct key *key, int *slot) | |||
133 | * level of the path (level 0) | 198 | * level of the path (level 0) |
134 | * | 199 | * |
135 | * If the key isn't found, the path points to the slot where it should | 200 | * If the key isn't found, the path points to the slot where it should |
136 | * be inserted. | 201 | * be inserted, and 1 is returned. If there are other errors during the |
202 | * search a negative error number is returned. | ||
137 | * | 203 | * |
138 | * if ins_len > 0, nodes and leaves will be split as we walk down the | 204 | * if ins_len > 0, nodes and leaves will be split as we walk down the |
139 | * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if | 205 | * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if |
@@ -153,6 +219,9 @@ int search_slot(struct ctree_root *root, struct key *key, | |||
153 | c = &b->node; | 219 | c = &b->node; |
154 | level = node_level(c->header.flags); | 220 | level = node_level(c->header.flags); |
155 | p->nodes[level] = b; | 221 | p->nodes[level] = b; |
222 | ret = check_block(p, level); | ||
223 | if (ret) | ||
224 | return -1; | ||
156 | ret = bin_search(c, key, &slot); | 225 | ret = bin_search(c, key, &slot); |
157 | if (!is_leaf(c->header.flags)) { | 226 | if (!is_leaf(c->header.flags)) { |
158 | if (ret && slot > 0) | 227 | if (ret && slot > 0) |
@@ -183,7 +252,7 @@ int search_slot(struct ctree_root *root, struct key *key, | |||
183 | return ret; | 252 | return ret; |
184 | } | 253 | } |
185 | } | 254 | } |
186 | return -1; | 255 | return 1; |
187 | } | 256 | } |
188 | 257 | ||
189 | /* | 258 | /* |
@@ -192,12 +261,17 @@ int search_slot(struct ctree_root *root, struct key *key, | |||
192 | * This is used after shifting pointers to the left, so it stops | 261 | * This is used after shifting pointers to the left, so it stops |
193 | * fixing up pointers when a given leaf/node is not in slot 0 of the | 262 | * fixing up pointers when a given leaf/node is not in slot 0 of the |
194 | * higher levels | 263 | * higher levels |
264 | * | ||
265 | * If this fails to write a tree block, it returns -1, but continues | ||
266 | * fixing up the blocks in ram so the tree is consistent. | ||
195 | */ | 267 | */ |
196 | static void fixup_low_keys(struct ctree_root *root, | 268 | static int fixup_low_keys(struct ctree_root *root, |
197 | struct ctree_path *path, struct key *key, | 269 | struct ctree_path *path, struct key *key, |
198 | int level) | 270 | int level) |
199 | { | 271 | { |
200 | int i; | 272 | int i; |
273 | int ret = 0; | ||
274 | int wret; | ||
201 | for (i = level; i < MAX_LEVEL; i++) { | 275 | for (i = level; i < MAX_LEVEL; i++) { |
202 | struct node *t; | 276 | struct node *t; |
203 | int tslot = path->slots[i]; | 277 | int tslot = path->slots[i]; |
@@ -205,10 +279,13 @@ static void fixup_low_keys(struct ctree_root *root, | |||
205 | break; | 279 | break; |
206 | t = &path->nodes[i]->node; | 280 | t = &path->nodes[i]->node; |
207 | memcpy(t->keys + tslot, key, sizeof(*key)); | 281 | memcpy(t->keys + tslot, key, sizeof(*key)); |
208 | write_tree_block(root, path->nodes[i]); | 282 | wret = write_tree_block(root, path->nodes[i]); |
283 | if (wret) | ||
284 | ret = wret; | ||
209 | if (tslot != 0) | 285 | if (tslot != 0) |
210 | break; | 286 | break; |
211 | } | 287 | } |
288 | return ret; | ||
212 | } | 289 | } |
213 | 290 | ||
214 | /* | 291 | /* |
@@ -220,8 +297,12 @@ static void fixup_low_keys(struct ctree_root *root, | |||
220 | * be modified to reflect the push. | 297 | * be modified to reflect the push. |
221 | * | 298 | * |
222 | * The path is altered to reflect the push. | 299 | * The path is altered to reflect the push. |
300 | * | ||
301 | * returns 0 if some ptrs were pushed left, < 0 if there was some horrible | ||
302 | * error, and > 0 if there was no room in the left hand block. | ||
223 | */ | 303 | */ |
224 | int push_node_left(struct ctree_root *root, struct ctree_path *path, int level) | 304 | static int push_node_left(struct ctree_root *root, struct ctree_path *path, |
305 | int level) | ||
225 | { | 306 | { |
226 | int slot; | 307 | int slot; |
227 | struct node *left; | 308 | struct node *left; |
@@ -231,6 +312,8 @@ int push_node_left(struct ctree_root *root, struct ctree_path *path, int level) | |||
231 | int right_nritems; | 312 | int right_nritems; |
232 | struct tree_buffer *t; | 313 | struct tree_buffer *t; |
233 | struct tree_buffer *right_buf; | 314 | struct tree_buffer *right_buf; |
315 | int ret = 0; | ||
316 | int wret; | ||
234 | 317 | ||
235 | if (level == MAX_LEVEL - 1 || path->nodes[level + 1] == 0) | 318 | if (level == MAX_LEVEL - 1 || path->nodes[level + 1] == 0) |
236 | return 1; | 319 | return 1; |
@@ -265,10 +348,17 @@ int push_node_left(struct ctree_root *root, struct ctree_path *path, int level) | |||
265 | left->header.nritems += push_items; | 348 | left->header.nritems += push_items; |
266 | 349 | ||
267 | /* adjust the pointers going up the tree */ | 350 | /* adjust the pointers going up the tree */ |
268 | fixup_low_keys(root, path, right->keys, level + 1); | 351 | wret = fixup_low_keys(root, path, right->keys, level + 1); |
352 | if (wret < 0) | ||
353 | ret = wret; | ||
269 | 354 | ||
270 | write_tree_block(root, t); | 355 | wret = write_tree_block(root, t); |
271 | write_tree_block(root, right_buf); | 356 | if (wret < 0) |
357 | ret = wret; | ||
358 | |||
359 | wret = write_tree_block(root, right_buf); | ||
360 | if (wret < 0) | ||
361 | ret = wret; | ||
272 | 362 | ||
273 | /* then fixup the leaf pointer in the path */ | 363 | /* then fixup the leaf pointer in the path */ |
274 | if (path->slots[level] < push_items) { | 364 | if (path->slots[level] < push_items) { |
@@ -280,7 +370,7 @@ int push_node_left(struct ctree_root *root, struct ctree_path *path, int level) | |||
280 | path->slots[level] -= push_items; | 370 | path->slots[level] -= push_items; |
281 | tree_block_release(root, t); | 371 | tree_block_release(root, t); |
282 | } | 372 | } |
283 | return 0; | 373 | return ret; |
284 | } | 374 | } |
285 | 375 | ||
286 | /* | 376 | /* |
@@ -292,8 +382,12 @@ int push_node_left(struct ctree_root *root, struct ctree_path *path, int level) | |||
292 | * be modified to reflect the push. | 382 | * be modified to reflect the push. |
293 | * | 383 | * |
294 | * The path is altered to reflect the push. | 384 | * The path is altered to reflect the push. |
385 | * | ||
386 | * returns 0 if some ptrs were pushed, < 0 if there was some horrible | ||
387 | * error, and > 0 if there was no room in the right hand block. | ||
295 | */ | 388 | */ |
296 | int push_node_right(struct ctree_root *root, struct ctree_path *path, int level) | 389 | static int push_node_right(struct ctree_root *root, struct ctree_path *path, |
390 | int level) | ||
297 | { | 391 | { |
298 | int slot; | 392 | int slot; |
299 | struct tree_buffer *t; | 393 | struct tree_buffer *t; |
@@ -368,6 +462,8 @@ int push_node_right(struct ctree_root *root, struct ctree_path *path, int level) | |||
368 | * helper function to insert a new root level in the tree. | 462 | * helper function to insert a new root level in the tree. |
369 | * A new node is allocated, and a single item is inserted to | 463 | * A new node is allocated, and a single item is inserted to |
370 | * point to the existing root | 464 | * point to the existing root |
465 | * | ||
466 | * returns zero on success or < 0 on failure. | ||
371 | */ | 467 | */ |
372 | static int insert_new_root(struct ctree_root *root, | 468 | static int insert_new_root(struct ctree_root *root, |
373 | struct ctree_path *path, int level) | 469 | struct ctree_path *path, int level) |
@@ -410,8 +506,10 @@ static int insert_new_root(struct ctree_root *root, | |||
410 | * | 506 | * |
411 | * slot and level indicate where you want the key to go, and | 507 | * slot and level indicate where you want the key to go, and |
412 | * blocknr is the block the key points to. | 508 | * blocknr is the block the key points to. |
509 | * | ||
510 | * returns zero on success and < 0 on any error | ||
413 | */ | 511 | */ |
414 | int insert_ptr(struct ctree_root *root, | 512 | static int insert_ptr(struct ctree_root *root, |
415 | struct ctree_path *path, struct key *key, | 513 | struct ctree_path *path, struct key *key, |
416 | u64 blocknr, int slot, int level) | 514 | u64 blocknr, int slot, int level) |
417 | { | 515 | { |
@@ -446,8 +544,11 @@ int insert_ptr(struct ctree_root *root, | |||
446 | * | 544 | * |
447 | * Before splitting this tries to make some room in the node by pushing | 545 | * Before splitting this tries to make some room in the node by pushing |
448 | * left and right, if either one works, it returns right away. | 546 | * left and right, if either one works, it returns right away. |
547 | * | ||
548 | * returns 0 on success and < 0 on failure | ||
449 | */ | 549 | */ |
450 | int split_node(struct ctree_root *root, struct ctree_path *path, int level) | 550 | static int split_node(struct ctree_root *root, struct ctree_path *path, |
551 | int level) | ||
451 | { | 552 | { |
452 | struct tree_buffer *t; | 553 | struct tree_buffer *t; |
453 | struct node *c; | 554 | struct node *c; |
@@ -455,13 +556,18 @@ int split_node(struct ctree_root *root, struct ctree_path *path, int level) | |||
455 | struct node *split; | 556 | struct node *split; |
456 | int mid; | 557 | int mid; |
457 | int ret; | 558 | int ret; |
559 | int wret; | ||
458 | 560 | ||
459 | ret = push_node_left(root, path, level); | 561 | ret = push_node_left(root, path, level); |
460 | if (!ret) | 562 | if (!ret) |
461 | return 0; | 563 | return 0; |
564 | if (ret < 0) | ||
565 | return ret; | ||
462 | ret = push_node_right(root, path, level); | 566 | ret = push_node_right(root, path, level); |
463 | if (!ret) | 567 | if (!ret) |
464 | return 0; | 568 | return 0; |
569 | if (ret < 0) | ||
570 | return ret; | ||
465 | t = path->nodes[level]; | 571 | t = path->nodes[level]; |
466 | c = &t->node; | 572 | c = &t->node; |
467 | if (t == root->node) { | 573 | if (t == root->node) { |
@@ -482,10 +588,19 @@ int split_node(struct ctree_root *root, struct ctree_path *path, int level) | |||
482 | (c->header.nritems - mid) * sizeof(u64)); | 588 | (c->header.nritems - mid) * sizeof(u64)); |
483 | split->header.nritems = c->header.nritems - mid; | 589 | split->header.nritems = c->header.nritems - mid; |
484 | c->header.nritems = mid; | 590 | c->header.nritems = mid; |
485 | write_tree_block(root, t); | 591 | ret = 0; |
486 | write_tree_block(root, split_buffer); | 592 | |
487 | insert_ptr(root, path, split->keys, split_buffer->blocknr, | 593 | wret = write_tree_block(root, t); |
488 | path->slots[level + 1] + 1, level + 1); | 594 | if (wret) |
595 | ret = wret; | ||
596 | wret = write_tree_block(root, split_buffer); | ||
597 | if (wret) | ||
598 | ret = wret; | ||
599 | wret = insert_ptr(root, path, split->keys, split_buffer->blocknr, | ||
600 | path->slots[level + 1] + 1, level + 1); | ||
601 | if (wret) | ||
602 | ret = wret; | ||
603 | |||
489 | if (path->slots[level] >= mid) { | 604 | if (path->slots[level] >= mid) { |
490 | path->slots[level] -= mid; | 605 | path->slots[level] -= mid; |
491 | tree_block_release(root, t); | 606 | tree_block_release(root, t); |
@@ -494,7 +609,7 @@ int split_node(struct ctree_root *root, struct ctree_path *path, int level) | |||
494 | } else { | 609 | } else { |
495 | tree_block_release(root, split_buffer); | 610 | tree_block_release(root, split_buffer); |
496 | } | 611 | } |
497 | return 0; | 612 | return ret; |
498 | } | 613 | } |
499 | 614 | ||
500 | /* | 615 | /* |
@@ -502,7 +617,7 @@ int split_node(struct ctree_root *root, struct ctree_path *path, int level) | |||
502 | * and nr indicate which items in the leaf to check. This totals up the | 617 | * and nr indicate which items in the leaf to check. This totals up the |
503 | * space used both by the item structs and the item data | 618 | * space used both by the item structs and the item data |
504 | */ | 619 | */ |
505 | int leaf_space_used(struct leaf *l, int start, int nr) | 620 | static int leaf_space_used(struct leaf *l, int start, int nr) |
506 | { | 621 | { |
507 | int data_len; | 622 | int data_len; |
508 | int end = start + nr - 1; | 623 | int end = start + nr - 1; |
@@ -518,9 +633,12 @@ int leaf_space_used(struct leaf *l, int start, int nr) | |||
518 | /* | 633 | /* |
519 | * push some data in the path leaf to the right, trying to free up at | 634 | * push some data in the path leaf to the right, trying to free up at |
520 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 635 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
636 | * | ||
637 | * returns 1 if the push failed because the other node didn't have enough | ||
638 | * room, 0 if everything worked out and < 0 if there were major errors. | ||
521 | */ | 639 | */ |
522 | int push_leaf_right(struct ctree_root *root, struct ctree_path *path, | 640 | static int push_leaf_right(struct ctree_root *root, struct ctree_path *path, |
523 | int data_size) | 641 | int data_size) |
524 | { | 642 | { |
525 | struct tree_buffer *left_buf = path->nodes[0]; | 643 | struct tree_buffer *left_buf = path->nodes[0]; |
526 | struct leaf *left = &left_buf->leaf; | 644 | struct leaf *left = &left_buf->leaf; |
@@ -609,8 +727,8 @@ int push_leaf_right(struct ctree_root *root, struct ctree_path *path, | |||
609 | * push some data in the path leaf to the left, trying to free up at | 727 | * push some data in the path leaf to the left, trying to free up at |
610 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 728 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
611 | */ | 729 | */ |
612 | int push_leaf_left(struct ctree_root *root, struct ctree_path *path, | 730 | static int push_leaf_left(struct ctree_root *root, struct ctree_path *path, |
613 | int data_size) | 731 | int data_size) |
614 | { | 732 | { |
615 | struct tree_buffer *right_buf = path->nodes[0]; | 733 | struct tree_buffer *right_buf = path->nodes[0]; |
616 | struct leaf *right = &right_buf->leaf; | 734 | struct leaf *right = &right_buf->leaf; |
@@ -623,6 +741,8 @@ int push_leaf_left(struct ctree_root *root, struct ctree_path *path, | |||
623 | int push_items = 0; | 741 | int push_items = 0; |
624 | struct item *item; | 742 | struct item *item; |
625 | int old_left_nritems; | 743 | int old_left_nritems; |
744 | int ret = 0; | ||
745 | int wret; | ||
626 | 746 | ||
627 | slot = path->slots[1]; | 747 | slot = path->slots[1]; |
628 | if (slot == 0) { | 748 | if (slot == 0) { |
@@ -681,10 +801,16 @@ int push_leaf_left(struct ctree_root *root, struct ctree_path *path, | |||
681 | push_space = right->items[i].offset; | 801 | push_space = right->items[i].offset; |
682 | } | 802 | } |
683 | 803 | ||
684 | write_tree_block(root, t); | 804 | wret = write_tree_block(root, t); |
685 | write_tree_block(root, right_buf); | 805 | if (wret) |
806 | ret = wret; | ||
807 | wret = write_tree_block(root, right_buf); | ||
808 | if (wret) | ||
809 | ret = wret; | ||
686 | 810 | ||
687 | fixup_low_keys(root, path, &right->items[0].key, 1); | 811 | wret = fixup_low_keys(root, path, &right->items[0].key, 1); |
812 | if (wret) | ||
813 | ret = wret; | ||
688 | 814 | ||
689 | /* then fixup the leaf pointer in the path */ | 815 | /* then fixup the leaf pointer in the path */ |
690 | if (path->slots[0] < push_items) { | 816 | if (path->slots[0] < push_items) { |
@@ -697,17 +823,20 @@ int push_leaf_left(struct ctree_root *root, struct ctree_path *path, | |||
697 | path->slots[0] -= push_items; | 823 | path->slots[0] -= push_items; |
698 | } | 824 | } |
699 | BUG_ON(path->slots[0] < 0); | 825 | BUG_ON(path->slots[0] < 0); |
700 | return 0; | 826 | return ret; |
701 | } | 827 | } |
702 | 828 | ||
703 | /* | 829 | /* |
704 | * split the path's leaf in two, making sure there is at least data_size | 830 | * split the path's leaf in two, making sure there is at least data_size |
705 | * available for the resulting leaf level of the path. | 831 | * available for the resulting leaf level of the path. |
832 | * | ||
833 | * returns 0 if all went well and < 0 on failure. | ||
706 | */ | 834 | */ |
707 | int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | 835 | static int split_leaf(struct ctree_root *root, struct ctree_path *path, |
836 | int data_size) | ||
708 | { | 837 | { |
709 | struct tree_buffer *l_buf = path->nodes[0]; | 838 | struct tree_buffer *l_buf; |
710 | struct leaf *l = &l_buf->leaf; | 839 | struct leaf *l; |
711 | int nritems; | 840 | int nritems; |
712 | int mid; | 841 | int mid; |
713 | int slot; | 842 | int slot; |
@@ -718,14 +847,23 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
718 | int rt_data_off; | 847 | int rt_data_off; |
719 | int i; | 848 | int i; |
720 | int ret; | 849 | int ret; |
721 | 850 | int wret; | |
722 | if (push_leaf_left(root, path, data_size) == 0 || | 851 | |
723 | push_leaf_right(root, path, data_size) == 0) { | 852 | wret = push_leaf_left(root, path, data_size); |
724 | l_buf = path->nodes[0]; | 853 | if (wret < 0) |
725 | l = &l_buf->leaf; | 854 | return wret; |
726 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) | 855 | if (wret) { |
727 | return 0; | 856 | wret = push_leaf_right(root, path, data_size); |
857 | if (wret < 0) | ||
858 | return wret; | ||
728 | } | 859 | } |
860 | l_buf = path->nodes[0]; | ||
861 | l = &l_buf->leaf; | ||
862 | |||
863 | /* did the pushes work? */ | ||
864 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) | ||
865 | return 0; | ||
866 | |||
729 | if (!path->nodes[1]) { | 867 | if (!path->nodes[1]) { |
730 | ret = insert_new_root(root, path, 1); | 868 | ret = insert_new_root(root, path, 1); |
731 | if (ret) | 869 | if (ret) |
@@ -768,10 +906,17 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
768 | right->items[i].offset += rt_data_off; | 906 | right->items[i].offset += rt_data_off; |
769 | 907 | ||
770 | l->header.nritems = mid; | 908 | l->header.nritems = mid; |
771 | ret = insert_ptr(root, path, &right->items[0].key, | 909 | ret = 0; |
910 | wret = insert_ptr(root, path, &right->items[0].key, | ||
772 | right_buffer->blocknr, path->slots[1] + 1, 1); | 911 | right_buffer->blocknr, path->slots[1] + 1, 1); |
773 | write_tree_block(root, right_buffer); | 912 | if (wret) |
774 | write_tree_block(root, l_buf); | 913 | ret = wret; |
914 | wret = write_tree_block(root, right_buffer); | ||
915 | if (wret) | ||
916 | ret = wret; | ||
917 | wret = write_tree_block(root, l_buf); | ||
918 | if (wret) | ||
919 | ret = wret; | ||
775 | 920 | ||
776 | BUG_ON(path->slots[0] != slot); | 921 | BUG_ON(path->slots[0] != slot); |
777 | if (mid <= slot) { | 922 | if (mid <= slot) { |
@@ -792,7 +937,8 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
792 | int insert_item(struct ctree_root *root, struct key *key, | 937 | int insert_item(struct ctree_root *root, struct key *key, |
793 | void *data, int data_size) | 938 | void *data, int data_size) |
794 | { | 939 | { |
795 | int ret; | 940 | int ret = 0; |
941 | int wret; | ||
796 | int slot; | 942 | int slot; |
797 | int slot_orig; | 943 | int slot_orig; |
798 | struct leaf *leaf; | 944 | struct leaf *leaf; |
@@ -810,6 +956,10 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
810 | release_path(root, &path); | 956 | release_path(root, &path); |
811 | return -EEXIST; | 957 | return -EEXIST; |
812 | } | 958 | } |
959 | if (ret < 0) { | ||
960 | release_path(root, &path); | ||
961 | return ret; | ||
962 | } | ||
813 | 963 | ||
814 | slot_orig = path.slots[0]; | 964 | slot_orig = path.slots[0]; |
815 | leaf_buf = path.nodes[0]; | 965 | leaf_buf = path.nodes[0]; |
@@ -850,13 +1000,19 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
850 | leaf->items[slot].size = data_size; | 1000 | leaf->items[slot].size = data_size; |
851 | memcpy(leaf->data + data_end - data_size, data, data_size); | 1001 | memcpy(leaf->data + data_end - data_size, data, data_size); |
852 | leaf->header.nritems += 1; | 1002 | leaf->header.nritems += 1; |
853 | write_tree_block(root, leaf_buf); | 1003 | |
1004 | ret = 0; | ||
854 | if (slot == 0) | 1005 | if (slot == 0) |
855 | fixup_low_keys(root, &path, key, 1); | 1006 | ret = fixup_low_keys(root, &path, key, 1); |
1007 | |||
1008 | wret = write_tree_block(root, leaf_buf); | ||
1009 | if (wret) | ||
1010 | ret = wret; | ||
1011 | |||
856 | if (leaf_free_space(leaf) < 0) | 1012 | if (leaf_free_space(leaf) < 0) |
857 | BUG(); | 1013 | BUG(); |
858 | release_path(root, &path); | 1014 | release_path(root, &path); |
859 | return 0; | 1015 | return ret; |
860 | } | 1016 | } |
861 | 1017 | ||
862 | /* | 1018 | /* |
@@ -866,13 +1022,15 @@ int insert_item(struct ctree_root *root, struct key *key, | |||
866 | * continuing all the way the root if required. The root is converted into | 1022 | * continuing all the way the root if required. The root is converted into |
867 | * a leaf if all the nodes are emptied. | 1023 | * a leaf if all the nodes are emptied. |
868 | */ | 1024 | */ |
869 | int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | 1025 | static int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) |
870 | { | 1026 | { |
871 | int slot; | 1027 | int slot; |
872 | struct tree_buffer *t; | 1028 | struct tree_buffer *t; |
873 | struct node *node; | 1029 | struct node *node; |
874 | int nritems; | 1030 | int nritems; |
875 | u64 blocknr; | 1031 | u64 blocknr; |
1032 | int wret; | ||
1033 | int ret = 0; | ||
876 | 1034 | ||
877 | while(1) { | 1035 | while(1) { |
878 | t = path->nodes[level]; | 1036 | t = path->nodes[level]; |
@@ -894,13 +1052,27 @@ int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | |||
894 | write_tree_block(root, t); | 1052 | write_tree_block(root, t); |
895 | if (node->header.nritems != 0) { | 1053 | if (node->header.nritems != 0) { |
896 | int tslot; | 1054 | int tslot; |
897 | if (slot == 0) | 1055 | if (slot == 0) { |
898 | fixup_low_keys(root, path, node->keys, | 1056 | wret = fixup_low_keys(root, path, |
899 | level + 1); | 1057 | node->keys, |
1058 | level + 1); | ||
1059 | if (wret) | ||
1060 | ret = wret; | ||
1061 | } | ||
900 | tslot = path->slots[level + 1]; | 1062 | tslot = path->slots[level + 1]; |
901 | t->count++; | 1063 | t->count++; |
902 | if (push_node_left(root, path, level)) | 1064 | wret = push_node_left(root, path, level); |
903 | push_node_right(root, path, level); | 1065 | if (wret < 0) { |
1066 | ret = wret; | ||
1067 | break; | ||
1068 | } | ||
1069 | if (node->header.nritems != 0) { | ||
1070 | wret = push_node_right(root, path, level); | ||
1071 | if (wret < 0) { | ||
1072 | ret = wret; | ||
1073 | break; | ||
1074 | } | ||
1075 | } | ||
904 | path->slots[level + 1] = tslot; | 1076 | path->slots[level + 1] = tslot; |
905 | if (node->header.nritems != 0) { | 1077 | if (node->header.nritems != 0) { |
906 | tree_block_release(root, t); | 1078 | tree_block_release(root, t); |
@@ -919,7 +1091,7 @@ int del_ptr(struct ctree_root *root, struct ctree_path *path, int level) | |||
919 | if (!path->nodes[level]) | 1091 | if (!path->nodes[level]) |
920 | BUG(); | 1092 | BUG(); |
921 | } | 1093 | } |
922 | return 0; | 1094 | return ret; |
923 | } | 1095 | } |
924 | 1096 | ||
925 | /* | 1097 | /* |
@@ -933,6 +1105,8 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
933 | struct tree_buffer *leaf_buf; | 1105 | struct tree_buffer *leaf_buf; |
934 | int doff; | 1106 | int doff; |
935 | int dsize; | 1107 | int dsize; |
1108 | int ret = 0; | ||
1109 | int wret; | ||
936 | 1110 | ||
937 | leaf_buf = path->nodes[0]; | 1111 | leaf_buf = path->nodes[0]; |
938 | leaf = &leaf_buf->leaf; | 1112 | leaf = &leaf_buf->leaf; |
@@ -959,14 +1133,23 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
959 | leaf->header.flags = node_level(0); | 1133 | leaf->header.flags = node_level(0); |
960 | write_tree_block(root, leaf_buf); | 1134 | write_tree_block(root, leaf_buf); |
961 | } else { | 1135 | } else { |
962 | del_ptr(root, path, 1); | 1136 | wret = del_ptr(root, path, 1); |
1137 | if (wret) | ||
1138 | ret = wret; | ||
963 | free_extent(root, leaf_buf->blocknr, 1); | 1139 | free_extent(root, leaf_buf->blocknr, 1); |
964 | } | 1140 | } |
965 | } else { | 1141 | } else { |
966 | int used = leaf_space_used(leaf, 0, leaf->header.nritems); | 1142 | int used = leaf_space_used(leaf, 0, leaf->header.nritems); |
967 | if (slot == 0) | 1143 | if (slot == 0) { |
968 | fixup_low_keys(root, path, &leaf->items[0].key, 1); | 1144 | wret = fixup_low_keys(root, path, |
969 | write_tree_block(root, leaf_buf); | 1145 | &leaf->items[0].key, 1); |
1146 | if (wret) | ||
1147 | ret = wret; | ||
1148 | } | ||
1149 | wret = write_tree_block(root, leaf_buf); | ||
1150 | if (wret) | ||
1151 | ret = wret; | ||
1152 | |||
970 | /* delete the leaf if it is mostly empty */ | 1153 | /* delete the leaf if it is mostly empty */ |
971 | if (used < LEAF_DATA_SIZE / 3) { | 1154 | if (used < LEAF_DATA_SIZE / 3) { |
972 | /* push_leaf_left fixes the path. | 1155 | /* push_leaf_left fixes the path. |
@@ -975,13 +1158,20 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
975 | */ | 1158 | */ |
976 | slot = path->slots[1]; | 1159 | slot = path->slots[1]; |
977 | leaf_buf->count++; | 1160 | leaf_buf->count++; |
978 | push_leaf_left(root, path, 1); | 1161 | wret = push_leaf_left(root, path, 1); |
979 | if (leaf->header.nritems) | 1162 | if (wret < 0) |
980 | push_leaf_right(root, path, 1); | 1163 | ret = wret; |
1164 | if (leaf->header.nritems) { | ||
1165 | wret = push_leaf_right(root, path, 1); | ||
1166 | if (wret < 0) | ||
1167 | ret = wret; | ||
1168 | } | ||
981 | if (leaf->header.nritems == 0) { | 1169 | if (leaf->header.nritems == 0) { |
982 | u64 blocknr = leaf_buf->blocknr; | 1170 | u64 blocknr = leaf_buf->blocknr; |
983 | path->slots[1] = slot; | 1171 | path->slots[1] = slot; |
984 | del_ptr(root, path, 1); | 1172 | wret = del_ptr(root, path, 1); |
1173 | if (wret) | ||
1174 | ret = wret; | ||
985 | tree_block_release(root, leaf_buf); | 1175 | tree_block_release(root, leaf_buf); |
986 | free_extent(root, blocknr, 1); | 1176 | free_extent(root, blocknr, 1); |
987 | } else { | 1177 | } else { |
@@ -989,7 +1179,7 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
989 | } | 1179 | } |
990 | } | 1180 | } |
991 | } | 1181 | } |
992 | return 0; | 1182 | return ret; |
993 | } | 1183 | } |
994 | 1184 | ||
995 | /* | 1185 | /* |
@@ -1033,165 +1223,3 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) | |||
1033 | return 0; | 1223 | return 0; |
1034 | } | 1224 | } |
1035 | 1225 | ||
1036 | /* some sample code to insert,search & delete items */ | ||
1037 | #if 0 | ||
1038 | /* for testing only */ | ||
1039 | int next_key(int i, int max_key) { | ||
1040 | return rand() % max_key; | ||
1041 | //return i; | ||
1042 | } | ||
1043 | int main() { | ||
1044 | struct key ins; | ||
1045 | struct key last = { (u64)-1, 0, 0}; | ||
1046 | char *buf; | ||
1047 | int i; | ||
1048 | int num; | ||
1049 | int ret; | ||
1050 | int run_size = 20000000; | ||
1051 | int max_key = 100000000; | ||
1052 | int tree_size = 0; | ||
1053 | struct ctree_path path; | ||
1054 | struct ctree_super_block super; | ||
1055 | struct ctree_root *root; | ||
1056 | |||
1057 | radix_tree_init(); | ||
1058 | |||
1059 | |||
1060 | root = open_ctree("dbfile", &super); | ||
1061 | srand(55); | ||
1062 | for (i = 0; i < run_size; i++) { | ||
1063 | buf = malloc(64); | ||
1064 | num = next_key(i, max_key); | ||
1065 | // num = i; | ||
1066 | sprintf(buf, "string-%d", num); | ||
1067 | if (i % 10000 == 0) | ||
1068 | fprintf(stderr, "insert %d:%d\n", num, i); | ||
1069 | ins.objectid = num; | ||
1070 | ins.offset = 0; | ||
1071 | ins.flags = 0; | ||
1072 | ret = insert_item(root, &ins, buf, strlen(buf)); | ||
1073 | if (!ret) | ||
1074 | tree_size++; | ||
1075 | free(buf); | ||
1076 | } | ||
1077 | write_ctree_super(root, &super); | ||
1078 | close_ctree(root); | ||
1079 | |||
1080 | root = open_ctree("dbfile", &super); | ||
1081 | printf("starting search\n"); | ||
1082 | srand(55); | ||
1083 | for (i = 0; i < run_size; i++) { | ||
1084 | num = next_key(i, max_key); | ||
1085 | ins.objectid = num; | ||
1086 | init_path(&path); | ||
1087 | if (i % 10000 == 0) | ||
1088 | fprintf(stderr, "search %d:%d\n", num, i); | ||
1089 | ret = search_slot(root, &ins, &path, 0); | ||
1090 | if (ret) { | ||
1091 | print_tree(root, root->node); | ||
1092 | printf("unable to find %d\n", num); | ||
1093 | exit(1); | ||
1094 | } | ||
1095 | release_path(root, &path); | ||
1096 | } | ||
1097 | write_ctree_super(root, &super); | ||
1098 | close_ctree(root); | ||
1099 | root = open_ctree("dbfile", &super); | ||
1100 | printf("node %p level %d total ptrs %d free spc %lu\n", root->node, | ||
1101 | node_level(root->node->node.header.flags), | ||
1102 | root->node->node.header.nritems, | ||
1103 | NODEPTRS_PER_BLOCK - root->node->node.header.nritems); | ||
1104 | printf("all searches good, deleting some items\n"); | ||
1105 | i = 0; | ||
1106 | srand(55); | ||
1107 | for (i = 0 ; i < run_size/4; i++) { | ||
1108 | num = next_key(i, max_key); | ||
1109 | ins.objectid = num; | ||
1110 | init_path(&path); | ||
1111 | ret = search_slot(root, &ins, &path, -1); | ||
1112 | if (!ret) { | ||
1113 | if (i % 10000 == 0) | ||
1114 | fprintf(stderr, "del %d:%d\n", num, i); | ||
1115 | ret = del_item(root, &path); | ||
1116 | if (ret != 0) | ||
1117 | BUG(); | ||
1118 | tree_size--; | ||
1119 | } | ||
1120 | release_path(root, &path); | ||
1121 | } | ||
1122 | write_ctree_super(root, &super); | ||
1123 | close_ctree(root); | ||
1124 | root = open_ctree("dbfile", &super); | ||
1125 | srand(128); | ||
1126 | for (i = 0; i < run_size; i++) { | ||
1127 | buf = malloc(64); | ||
1128 | num = next_key(i, max_key); | ||
1129 | sprintf(buf, "string-%d", num); | ||
1130 | ins.objectid = num; | ||
1131 | if (i % 10000 == 0) | ||
1132 | fprintf(stderr, "insert %d:%d\n", num, i); | ||
1133 | ret = insert_item(root, &ins, buf, strlen(buf)); | ||
1134 | if (!ret) | ||
1135 | tree_size++; | ||
1136 | free(buf); | ||
1137 | } | ||
1138 | write_ctree_super(root, &super); | ||
1139 | close_ctree(root); | ||
1140 | root = open_ctree("dbfile", &super); | ||
1141 | srand(128); | ||
1142 | printf("starting search2\n"); | ||
1143 | for (i = 0; i < run_size; i++) { | ||
1144 | num = next_key(i, max_key); | ||
1145 | ins.objectid = num; | ||
1146 | init_path(&path); | ||
1147 | if (i % 10000 == 0) | ||
1148 | fprintf(stderr, "search %d:%d\n", num, i); | ||
1149 | ret = search_slot(root, &ins, &path, 0); | ||
1150 | if (ret) { | ||
1151 | print_tree(root, root->node); | ||
1152 | printf("unable to find %d\n", num); | ||
1153 | exit(1); | ||
1154 | } | ||
1155 | release_path(root, &path); | ||
1156 | } | ||
1157 | printf("starting big long delete run\n"); | ||
1158 | while(root->node && root->node->node.header.nritems > 0) { | ||
1159 | struct leaf *leaf; | ||
1160 | int slot; | ||
1161 | ins.objectid = (u64)-1; | ||
1162 | init_path(&path); | ||
1163 | ret = search_slot(root, &ins, &path, -1); | ||
1164 | if (ret == 0) | ||
1165 | BUG(); | ||
1166 | |||
1167 | leaf = &path.nodes[0]->leaf; | ||
1168 | slot = path.slots[0]; | ||
1169 | if (slot != leaf->header.nritems) | ||
1170 | BUG(); | ||
1171 | while(path.slots[0] > 0) { | ||
1172 | path.slots[0] -= 1; | ||
1173 | slot = path.slots[0]; | ||
1174 | leaf = &path.nodes[0]->leaf; | ||
1175 | |||
1176 | if (comp_keys(&last, &leaf->items[slot].key) <= 0) | ||
1177 | BUG(); | ||
1178 | memcpy(&last, &leaf->items[slot].key, sizeof(last)); | ||
1179 | if (tree_size % 10000 == 0) | ||
1180 | printf("big del %d:%d\n", tree_size, i); | ||
1181 | ret = del_item(root, &path); | ||
1182 | if (ret != 0) { | ||
1183 | printf("del_item returned %d\n", ret); | ||
1184 | BUG(); | ||
1185 | } | ||
1186 | tree_size--; | ||
1187 | } | ||
1188 | release_path(root, &path); | ||
1189 | } | ||
1190 | printf("tree size is now %d\n", tree_size); | ||
1191 | printf("map tree\n"); | ||
1192 | print_tree(root->extent_root, root->extent_root->node); | ||
1193 | write_ctree_super(root, &super); | ||
1194 | close_ctree(root); | ||
1195 | return 0; | ||
1196 | } | ||
1197 | #endif | ||