diff options
-rw-r--r-- | fs/btrfs/ctree.c | 109 |
1 files changed, 102 insertions, 7 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index e497fd963118..ef8bfa837532 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -518,6 +518,97 @@ int leaf_space_used(struct leaf *l, int start, int nr) | |||
518 | } | 518 | } |
519 | 519 | ||
520 | /* | 520 | /* |
521 | * push some data in the path leaf to the right, trying to free up at | ||
522 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | ||
523 | */ | ||
524 | int push_leaf_right(struct ctree_root *root, struct ctree_path *path, | ||
525 | int data_size) | ||
526 | { | ||
527 | struct tree_buffer *left_buf = path->nodes[0]; | ||
528 | struct leaf *left = &left_buf->leaf; | ||
529 | struct leaf *right; | ||
530 | struct tree_buffer *right_buf; | ||
531 | struct tree_buffer *upper; | ||
532 | int slot; | ||
533 | int i; | ||
534 | int free_space; | ||
535 | int push_space = 0; | ||
536 | int push_items = 0; | ||
537 | struct item *item; | ||
538 | |||
539 | slot = path->slots[1]; | ||
540 | if (!path->nodes[1]) { | ||
541 | return 1; | ||
542 | } | ||
543 | upper = path->nodes[1]; | ||
544 | if (slot >= upper->node.header.nritems - 1) { | ||
545 | return 1; | ||
546 | } | ||
547 | right_buf = read_tree_block(root, upper->node.blockptrs[slot + 1]); | ||
548 | right = &right_buf->leaf; | ||
549 | free_space = leaf_free_space(right); | ||
550 | if (free_space < data_size + sizeof(struct item)) { | ||
551 | tree_block_release(root, right_buf); | ||
552 | return 1; | ||
553 | } | ||
554 | for (i = left->header.nritems - 1; i >= 0; i--) { | ||
555 | item = left->items + i; | ||
556 | if (path->slots[0] == i) | ||
557 | push_space += data_size + sizeof(*item); | ||
558 | if (item->size + sizeof(*item) + push_space > free_space) | ||
559 | break; | ||
560 | push_items++; | ||
561 | push_space += item->size + sizeof(*item); | ||
562 | } | ||
563 | if (push_items == 0) { | ||
564 | tree_block_release(root, right_buf); | ||
565 | return 1; | ||
566 | } | ||
567 | /* push left to right */ | ||
568 | push_space = left->items[left->header.nritems - push_items].offset + | ||
569 | left->items[left->header.nritems - push_items].size; | ||
570 | push_space -= leaf_data_end(left); | ||
571 | /* make room in the right data area */ | ||
572 | memmove(right->data + leaf_data_end(right) - push_space, | ||
573 | right->data + leaf_data_end(right), | ||
574 | LEAF_DATA_SIZE - leaf_data_end(right)); | ||
575 | /* copy from the left data area */ | ||
576 | memcpy(right->data + LEAF_DATA_SIZE - push_space, | ||
577 | left->data + leaf_data_end(left), | ||
578 | push_space); | ||
579 | memmove(right->items + push_items, right->items, | ||
580 | right->header.nritems * sizeof(struct item)); | ||
581 | /* copy the items from left to right */ | ||
582 | memcpy(right->items, left->items + left->header.nritems - push_items, | ||
583 | push_items * sizeof(struct item)); | ||
584 | |||
585 | /* update the item pointers */ | ||
586 | right->header.nritems += push_items; | ||
587 | push_space = LEAF_DATA_SIZE; | ||
588 | for (i = 0; i < right->header.nritems; i++) { | ||
589 | right->items[i].offset = push_space - right->items[i].size; | ||
590 | push_space = right->items[i].offset; | ||
591 | } | ||
592 | left->header.nritems -= push_items; | ||
593 | |||
594 | write_tree_block(root, left_buf); | ||
595 | write_tree_block(root, right_buf); | ||
596 | memcpy(upper->node.keys + slot + 1, | ||
597 | &right->items[0].key, sizeof(struct key)); | ||
598 | write_tree_block(root, upper); | ||
599 | /* then fixup the leaf pointer in the path */ | ||
600 | // FIXME use nritems in here somehow | ||
601 | if (path->slots[0] >= left->header.nritems) { | ||
602 | path->slots[0] -= left->header.nritems; | ||
603 | tree_block_release(root, path->nodes[0]); | ||
604 | path->nodes[0] = right_buf; | ||
605 | path->slots[1] += 1; | ||
606 | } else { | ||
607 | tree_block_release(root, right_buf); | ||
608 | } | ||
609 | return 0; | ||
610 | } | ||
611 | /* | ||
521 | * push some data in the path leaf to the left, trying to free up at | 612 | * push some data in the path leaf to the left, trying to free up at |
522 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 613 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
523 | */ | 614 | */ |
@@ -631,7 +722,8 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) | |||
631 | int i; | 722 | int i; |
632 | int ret; | 723 | int ret; |
633 | 724 | ||
634 | if (push_leaf_left(root, path, data_size) == 0) { | 725 | if (push_leaf_left(root, path, data_size) == 0 || |
726 | push_leaf_right(root, path, data_size) == 0) { | ||
635 | l_buf = path->nodes[0]; | 727 | l_buf = path->nodes[0]; |
636 | l = &l_buf->leaf; | 728 | l = &l_buf->leaf; |
637 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) | 729 | if (leaf_free_space(l) >= sizeof(struct item) + data_size) |
@@ -875,6 +967,8 @@ int del_item(struct ctree_root *root, struct ctree_path *path) | |||
875 | slot = path->slots[1]; | 967 | slot = path->slots[1]; |
876 | leaf_buf->count++; | 968 | leaf_buf->count++; |
877 | push_leaf_left(root, path, 1); | 969 | push_leaf_left(root, path, 1); |
970 | if (leaf->header.nritems) | ||
971 | push_leaf_right(root, path, 1); | ||
878 | if (leaf->header.nritems == 0) { | 972 | if (leaf->header.nritems == 0) { |
879 | u64 blocknr = leaf_buf->blocknr; | 973 | u64 blocknr = leaf_buf->blocknr; |
880 | path->slots[1] = slot; | 974 | path->slots[1] = slot; |
@@ -929,7 +1023,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) | |||
929 | /* for testing only */ | 1023 | /* for testing only */ |
930 | int next_key(int i, int max_key) { | 1024 | int next_key(int i, int max_key) { |
931 | return rand() % max_key; | 1025 | return rand() % max_key; |
932 | // return i; | 1026 | //return i; |
933 | } | 1027 | } |
934 | 1028 | ||
935 | int main() { | 1029 | int main() { |
@@ -958,7 +1052,7 @@ int main() { | |||
958 | // num = i; | 1052 | // num = i; |
959 | sprintf(buf, "string-%d", num); | 1053 | sprintf(buf, "string-%d", num); |
960 | if (i % 10000 == 0) | 1054 | if (i % 10000 == 0) |
961 | printf("insert %d:%d\n", num, i); | 1055 | fprintf(stderr, "insert %d:%d\n", num, i); |
962 | ins.objectid = num; | 1056 | ins.objectid = num; |
963 | ins.offset = 0; | 1057 | ins.offset = 0; |
964 | ins.flags = 0; | 1058 | ins.flags = 0; |
@@ -978,7 +1072,7 @@ int main() { | |||
978 | ins.objectid = num; | 1072 | ins.objectid = num; |
979 | init_path(&path); | 1073 | init_path(&path); |
980 | if (i % 10000 == 0) | 1074 | if (i % 10000 == 0) |
981 | printf("search %d:%d\n", num, i); | 1075 | fprintf(stderr, "search %d:%d\n", num, i); |
982 | ret = search_slot(root, &ins, &path, 0); | 1076 | ret = search_slot(root, &ins, &path, 0); |
983 | if (ret) { | 1077 | if (ret) { |
984 | print_tree(root, root->node); | 1078 | print_tree(root, root->node); |
@@ -1004,7 +1098,7 @@ int main() { | |||
1004 | ret = search_slot(root, &ins, &path, -1); | 1098 | ret = search_slot(root, &ins, &path, -1); |
1005 | if (!ret) { | 1099 | if (!ret) { |
1006 | if (i % 10000 == 0) | 1100 | if (i % 10000 == 0) |
1007 | printf("del %d:%d\n", num, i); | 1101 | fprintf(stderr, "del %d:%d\n", num, i); |
1008 | ret = del_item(root, &path); | 1102 | ret = del_item(root, &path); |
1009 | if (ret != 0) | 1103 | if (ret != 0) |
1010 | BUG(); | 1104 | BUG(); |
@@ -1022,7 +1116,7 @@ int main() { | |||
1022 | sprintf(buf, "string-%d", num); | 1116 | sprintf(buf, "string-%d", num); |
1023 | ins.objectid = num; | 1117 | ins.objectid = num; |
1024 | if (i % 10000 == 0) | 1118 | if (i % 10000 == 0) |
1025 | printf("insert %d:%d\n", num, i); | 1119 | fprintf(stderr, "insert %d:%d\n", num, i); |
1026 | ret = insert_item(root, &ins, buf, strlen(buf)); | 1120 | ret = insert_item(root, &ins, buf, strlen(buf)); |
1027 | if (!ret) | 1121 | if (!ret) |
1028 | tree_size++; | 1122 | tree_size++; |
@@ -1038,7 +1132,7 @@ int main() { | |||
1038 | ins.objectid = num; | 1132 | ins.objectid = num; |
1039 | init_path(&path); | 1133 | init_path(&path); |
1040 | if (i % 10000 == 0) | 1134 | if (i % 10000 == 0) |
1041 | printf("search %d:%d\n", num, i); | 1135 | fprintf(stderr, "search %d:%d\n", num, i); |
1042 | ret = search_slot(root, &ins, &path, 0); | 1136 | ret = search_slot(root, &ins, &path, 0); |
1043 | if (ret) { | 1137 | if (ret) { |
1044 | print_tree(root, root->node); | 1138 | print_tree(root, root->node); |
@@ -1082,6 +1176,7 @@ int main() { | |||
1082 | } | 1176 | } |
1083 | printf("tree size is now %d\n", tree_size); | 1177 | printf("tree size is now %d\n", tree_size); |
1084 | printf("map tree\n"); | 1178 | printf("map tree\n"); |
1179 | print_tree(root->extent_root, root->extent_root->node); | ||
1085 | write_ctree_super(root, &super); | 1180 | write_ctree_super(root, &super); |
1086 | close_ctree(root); | 1181 | close_ctree(root); |
1087 | return 0; | 1182 | return 0; |