aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.c109
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 */
524int 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 */
930int next_key(int i, int max_key) { 1024int 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
935int main() { 1029int 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;