summaryrefslogtreecommitdiff
path: root/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-24 14:46:15 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2008-04-24 14:46:15 -0400
commit309ce6768b29f72815ab8301b3670c7d8f7af307 (patch)
treeb458a2d6e8eb7321f2257e004e199ac9ec9713f3 /ctree.c
parent8057a6c3e739fa09b1a9398c13e00fd3c70fe939 (diff)
downloadbtrfs-progs-309ce6768b29f72815ab8301b3670c7d8f7af307.tar.gz
Fix balance_level to free the middle block if there is room in the left one
balance level starts by trying to empty the middle block, and then pushes from the right to the middle. This might empty the right block and leave a small number of pointers in the middle.
Diffstat (limited to 'ctree.c')
-rw-r--r--ctree.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/ctree.c b/ctree.c
index eb645da..5608bb4 100644
--- a/ctree.c
+++ b/ctree.c
@@ -745,7 +745,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* first, try to make some room in the middle buffer */
if (left) {
orig_slot += btrfs_header_nritems(left);
- wret = push_node_left(trans, root, left, mid, 0);
+ wret = push_node_left(trans, root, left, mid, 1);
if (wret < 0)
ret = wret;
if (btrfs_header_nritems(mid) < 2)
@@ -801,6 +801,11 @@ static int balance_level(struct btrfs_trans_handle *trans,
ret = wret;
goto enospc;
}
+ if (wret == 1) {
+ wret = push_node_left(trans, root, left, mid, 1);
+ if (wret < 0)
+ ret = wret;
+ }
BUG_ON(wret == 1);
}
if (btrfs_header_nritems(mid) == 0) {
@@ -1213,17 +1218,27 @@ static int push_node_left(struct btrfs_trans_handle *trans,
WARN_ON(btrfs_header_generation(src) != trans->transid);
WARN_ON(btrfs_header_generation(dst) != trans->transid);
- if (!empty && src_nritems <= 2)
+ if (!empty && src_nritems <= 8)
return 1;
if (push_items <= 0) {
return 1;
}
- if (empty)
+ if (empty) {
push_items = min(src_nritems, push_items);
- else
- push_items = min(src_nritems - 2, push_items);
+ if (push_items < src_nritems) {
+ /* leave at least 8 pointers in the node if
+ * we aren't going to empty it
+ */
+ if (src_nritems - push_items < 8) {
+ if (push_items <= 8)
+ return 1;
+ push_items -= 8;
+ }
+ }
+ } else
+ push_items = min(src_nritems - 8, push_items);
copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(dst_nritems),
@@ -1269,13 +1284,19 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
src_nritems = btrfs_header_nritems(src);
dst_nritems = btrfs_header_nritems(dst);
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
- if (push_items <= 0)
+ if (push_items <= 0) {
return 1;
+ }
+
+ if (src_nritems < 4) {
+ return 1;
+ }
max_push = src_nritems / 2 + 1;
/* don't try to empty the node */
- if (max_push >= src_nritems)
+ if (max_push >= src_nritems) {
return 1;
+ }
if (max_push < push_items)
push_items = max_push;