aboutsummaryrefslogtreecommitdiff
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-24 14:42:46 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commitbce4eae9864e6b6ebde5d7f05576ff0a6c3724d0 (patch)
tree87e90c0e7b7a75b9df5c062504a86c0424cade68 /fs/btrfs
parent971a1f6648bfafd4239234f1ffb9c26e907c2744 (diff)
Btrfs: 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. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c35
-rw-r--r--fs/btrfs/extent-tree.c4
2 files changed, 30 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 319f9f9bf8d..29e5674b043 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -789,7 +789,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)
@@ -844,6 +844,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) {
@@ -1252,17 +1257,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),
@@ -1308,13 +1323,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;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index cc0d7f30c36..c49592c5127 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -306,13 +306,13 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
int bit;
int ret;
int full_search = 0;
- int factor = 8;
+ int factor = 10;
block_group_cache = &info->block_group_cache;
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
if (!owner)
- factor = 8;
+ factor = 10;
bit = block_group_state_bits(data);