aboutsummaryrefslogtreecommitdiffstats
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
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>
-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 319f9f9bf8d4..29e5674b043d 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -789,7 +789,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
789 /* first, try to make some room in the middle buffer */ 789 /* first, try to make some room in the middle buffer */
790 if (left) { 790 if (left) {
791 orig_slot += btrfs_header_nritems(left); 791 orig_slot += btrfs_header_nritems(left);
792 wret = push_node_left(trans, root, left, mid, 0); 792 wret = push_node_left(trans, root, left, mid, 1);
793 if (wret < 0) 793 if (wret < 0)
794 ret = wret; 794 ret = wret;
795 if (btrfs_header_nritems(mid) < 2) 795 if (btrfs_header_nritems(mid) < 2)
@@ -844,6 +844,11 @@ static int balance_level(struct btrfs_trans_handle *trans,
844 ret = wret; 844 ret = wret;
845 goto enospc; 845 goto enospc;
846 } 846 }
847 if (wret == 1) {
848 wret = push_node_left(trans, root, left, mid, 1);
849 if (wret < 0)
850 ret = wret;
851 }
847 BUG_ON(wret == 1); 852 BUG_ON(wret == 1);
848 } 853 }
849 if (btrfs_header_nritems(mid) == 0) { 854 if (btrfs_header_nritems(mid) == 0) {
@@ -1252,17 +1257,27 @@ static int push_node_left(struct btrfs_trans_handle *trans,
1252 WARN_ON(btrfs_header_generation(src) != trans->transid); 1257 WARN_ON(btrfs_header_generation(src) != trans->transid);
1253 WARN_ON(btrfs_header_generation(dst) != trans->transid); 1258 WARN_ON(btrfs_header_generation(dst) != trans->transid);
1254 1259
1255 if (!empty && src_nritems <= 2) 1260 if (!empty && src_nritems <= 8)
1256 return 1; 1261 return 1;
1257 1262
1258 if (push_items <= 0) { 1263 if (push_items <= 0) {
1259 return 1; 1264 return 1;
1260 } 1265 }
1261 1266
1262 if (empty) 1267 if (empty) {
1263 push_items = min(src_nritems, push_items); 1268 push_items = min(src_nritems, push_items);
1264 else 1269 if (push_items < src_nritems) {
1265 push_items = min(src_nritems - 2, push_items); 1270 /* leave at least 8 pointers in the node if
1271 * we aren't going to empty it
1272 */
1273 if (src_nritems - push_items < 8) {
1274 if (push_items <= 8)
1275 return 1;
1276 push_items -= 8;
1277 }
1278 }
1279 } else
1280 push_items = min(src_nritems - 8, push_items);
1266 1281
1267 copy_extent_buffer(dst, src, 1282 copy_extent_buffer(dst, src,
1268 btrfs_node_key_ptr_offset(dst_nritems), 1283 btrfs_node_key_ptr_offset(dst_nritems),
@@ -1308,13 +1323,19 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
1308 src_nritems = btrfs_header_nritems(src); 1323 src_nritems = btrfs_header_nritems(src);
1309 dst_nritems = btrfs_header_nritems(dst); 1324 dst_nritems = btrfs_header_nritems(dst);
1310 push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; 1325 push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
1311 if (push_items <= 0) 1326 if (push_items <= 0) {
1312 return 1; 1327 return 1;
1328 }
1329
1330 if (src_nritems < 4) {
1331 return 1;
1332 }
1313 1333
1314 max_push = src_nritems / 2 + 1; 1334 max_push = src_nritems / 2 + 1;
1315 /* don't try to empty the node */ 1335 /* don't try to empty the node */
1316 if (max_push >= src_nritems) 1336 if (max_push >= src_nritems) {
1317 return 1; 1337 return 1;
1338 }
1318 1339
1319 if (max_push < push_items) 1340 if (max_push < push_items)
1320 push_items = max_push; 1341 push_items = max_push;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index cc0d7f30c36b..c49592c5127a 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,
306 int bit; 306 int bit;
307 int ret; 307 int ret;
308 int full_search = 0; 308 int full_search = 0;
309 int factor = 8; 309 int factor = 10;
310 310
311 block_group_cache = &info->block_group_cache; 311 block_group_cache = &info->block_group_cache;
312 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); 312 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
313 313
314 if (!owner) 314 if (!owner)
315 factor = 8; 315 factor = 10;
316 316
317 bit = block_group_state_bits(data); 317 bit = block_group_state_bits(data);
318 318