Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 128257
b: refs/heads/master
c: 79f95c8
h: refs/heads/master
i:
  128255: ad8077d
v: v3
  • Loading branch information
Chris Mason authored and David Woodhouse committed Mar 1, 2007
1 parent 8df92a3 commit 0b86bee
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 44 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bb8039515d7c1b521ea22f095b43618ccc771885
refs/heads/master: 79f95c82dca7665f32bafd68b7cdf4a01fab0840
5 changes: 4 additions & 1 deletion trunk/fs/btrfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ check=sparse $(CHECKFLAGS)
$(check) $<
$(CC) $(CFLAGS) -c $<

all: tester debug-tree
all: tester debug-tree quick-test

debug-tree: $(objects) debug-tree.o
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o

tester: $(objects) random-test.o
gcc $(CFLAGS) -o tester $(objects) random-test.o

quick-test: $(objects) quick-test.o
gcc $(CFLAGS) -o quick-test $(objects) quick-test.o

$(objects) : $(headers)

clean :
Expand Down
137 changes: 113 additions & 24 deletions trunk/fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ static int split_leaf(struct ctree_root *root, struct ctree_path *path,
int data_size);
static int push_node_left(struct ctree_root *root, struct tree_buffer *dst,
struct tree_buffer *src);
static int balance_node_right(struct ctree_root *root,
struct tree_buffer *dst_buf,
struct tree_buffer *src_buf);
static int del_ptr(struct ctree_root *root, struct ctree_path *path, int level,
int slot);

Expand Down Expand Up @@ -217,15 +220,16 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
int ret = 0;
int wret;
int pslot;
int used = 0;
int count;
int orig_slot = path->slots[level];
u64 orig_ptr;

if (level == 0)
return 0;

mid_buf = path->nodes[level];
mid = &mid_buf->node;
orig_ptr = mid->blockptrs[orig_slot];

if (level < MAX_LEVEL - 1)
parent_buf = path->nodes[level + 1];
pslot = path->slots[level + 1];
Expand Down Expand Up @@ -253,24 +257,26 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
if (mid->header.nritems > NODEPTRS_PER_BLOCK / 4)
return 0;

// print_tree(root, root->node);
left_buf = read_node_slot(root, parent_buf, pslot - 1);
right_buf = read_node_slot(root, parent_buf, pslot + 1);
if (right_buf) {
right = &right_buf->node;
used = right->header.nritems;
count = 1;
}

/* first, try to make some room in the middle buffer */
if (left_buf) {
left = &left_buf->node;
used += left->header.nritems;
orig_slot += left->header.nritems;
count++;
wret = push_node_left(root, left_buf, mid_buf);
if (wret < 0)
ret = wret;
}
if (left_buf)
push_node_left(root, left_buf, mid_buf);

/*
* then try to empty the right most buffer into the middle
*/
if (right_buf) {
push_node_left(root, mid_buf, right_buf);
right = &right_buf->node;
wret = push_node_left(root, mid_buf, right_buf);
if (wret < 0)
ret = wret;
if (right->header.nritems == 0) {
u64 blocknr = right_buf->blocknr;
tree_block_release(root, right_buf);
Expand All @@ -285,9 +291,29 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
} else {
memcpy(parent->keys + pslot + 1, right->keys,
sizeof(struct key));
wret = write_tree_block(root, parent_buf);
if (wret)
ret = wret;
}
}
if (mid->header.nritems == 1) {
/*
* we're not allowed to leave a node with one item in the
* tree during a delete. A deletion from lower in the tree
* could try to delete the only pointer in this node.
* So, pull some keys from the left.
* There has to be a left pointer at this point because
* otherwise we would have pulled some pointers from the
* right
*/
BUG_ON(!left_buf);
wret = balance_node_right(root, mid_buf, left_buf);
if (wret < 0)
ret = wret;
BUG_ON(wret == 1);
}
if (mid->header.nritems == 0) {
/* we've managed to empty the middle node, drop it */
u64 blocknr = mid_buf->blocknr;
tree_block_release(root, mid_buf);
mid_buf = NULL;
Expand All @@ -298,11 +324,17 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
wret = free_extent(root, blocknr, 1);
if (wret)
ret = wret;
} else
} else {
/* update the parent key to reflect our changes */
memcpy(parent->keys + pslot, mid->keys, sizeof(struct key));
wret = write_tree_block(root, parent_buf);
if (wret)
ret = wret;
}

/* update the path */
if (left_buf) {
if (left->header.nritems >= orig_slot) {
if (left->header.nritems > orig_slot) {
left_buf->count++; // released below
path->nodes[level] = left_buf;
path->slots[level + 1] -= 1;
Expand All @@ -314,12 +346,15 @@ static int balance_level(struct ctree_root *root, struct ctree_path *path,
path->slots[level] = orig_slot;
}
}
/* double check we haven't messed things up */
check_block(path, level);
if (orig_ptr != path->nodes[level]->node.blockptrs[path->slots[level]])
BUG();

if (right_buf)
tree_block_release(root, right_buf);
if (left_buf)
tree_block_release(root, left_buf);

return ret;
}

Expand Down Expand Up @@ -378,6 +413,7 @@ int search_slot(struct ctree_root *root, struct key *key,
goto again;
c = &b->node;
slot = p->slots[level];
BUG_ON(c->header.nritems == 1);
}
b = read_tree_block(root, c->blockptrs[slot]);
} else {
Expand Down Expand Up @@ -433,13 +469,7 @@ static int fixup_low_keys(struct ctree_root *root,

/*
* try to push data from one node into the next node left in the
* tree. The src node is found at specified level in the path.
* If some bytes were pushed, return 0, otherwise return 1.
*
* Lower nodes/leaves in the path are not touched, higher nodes may
* be modified to reflect the push.
*
* The path is altered to reflect the push.
* tree.
*
* returns 0 if some ptrs were pushed left, < 0 if there was some horrible
* error, and > 0 if there was no room in the left hand block.
Expand All @@ -463,7 +493,8 @@ static int push_node_left(struct ctree_root *root, struct tree_buffer *dst_buf,
}

if (src_nritems < push_items)
push_items =src_nritems;
push_items = src_nritems;

memcpy(dst->keys + dst_nritems, src->keys,
push_items * sizeof(struct key));
memcpy(dst->blockptrs + dst_nritems, src->blockptrs,
Expand All @@ -487,6 +518,64 @@ static int push_node_left(struct ctree_root *root, struct tree_buffer *dst_buf,
return ret;
}

/*
* try to push data from one node into the next node right in the
* tree.
*
* returns 0 if some ptrs were pushed, < 0 if there was some horrible
* error, and > 0 if there was no room in the right hand block.
*
* this will only push up to 1/2 the contents of the left node over
*/
static int balance_node_right(struct ctree_root *root,
struct tree_buffer *dst_buf,
struct tree_buffer *src_buf)
{
struct node *src = &src_buf->node;
struct node *dst = &dst_buf->node;
int push_items = 0;
int max_push;
int src_nritems;
int dst_nritems;
int ret = 0;
int wret;

src_nritems = src->header.nritems;
dst_nritems = dst->header.nritems;
push_items = NODEPTRS_PER_BLOCK - dst_nritems;
if (push_items <= 0) {
return 1;
}

max_push = src_nritems / 2 + 1;
/* don't try to empty the node */
if (max_push > src_nritems)
return 1;
if (max_push < push_items)
push_items = max_push;

memmove(dst->keys + push_items, dst->keys,
dst_nritems * sizeof(struct key));
memmove(dst->blockptrs + push_items, dst->blockptrs,
dst_nritems * sizeof(u64));
memcpy(dst->keys, src->keys + src_nritems - push_items,
push_items * sizeof(struct key));
memcpy(dst->blockptrs, src->blockptrs + src_nritems - push_items,
push_items * sizeof(u64));

src->header.nritems -= push_items;
dst->header.nritems += push_items;

wret = write_tree_block(root, src_buf);
if (wret < 0)
ret = wret;

wret = write_tree_block(root, dst_buf);
if (wret < 0)
ret = wret;
return ret;
}

/*
* helper function to insert a new root level in the tree.
* A new node is allocated, and a single item is inserted to
Expand Down
Loading

0 comments on commit 0b86bee

Please sign in to comment.