aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-03-13 10:24:59 -0400
committerChris Mason <chris.mason@oracle.com>2009-03-24 16:14:25 -0400
commit9fa8cfe706f9c20067c042a064999d5825a35330 (patch)
tree8e64281caffcdb3ad5a8ab8bf22bb90483e9e214 /fs/btrfs
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
Btrfs: don't preallocate metadata blocks during btrfs_search_slot
In order to avoid doing expensive extent management with tree locks held, btrfs_search_slot will preallocate tree blocks for use by COW without any tree locks held. A later commit moves all of the extent allocation work for COW into a delayed update mechanism, and this preallocation will no longer be required. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c100
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/transaction.c4
3 files changed, 21 insertions, 85 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 37f31b5529aa..87c90387283b 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -254,18 +254,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
254 * empty_size -- a hint that you plan on doing more cow. This is the size in 254 * empty_size -- a hint that you plan on doing more cow. This is the size in
255 * bytes the allocator should try to find free next to the block it returns. 255 * bytes the allocator should try to find free next to the block it returns.
256 * This is just a hint and may be ignored by the allocator. 256 * This is just a hint and may be ignored by the allocator.
257 *
258 * prealloc_dest -- if you have already reserved a destination for the cow,
259 * this uses that block instead of allocating a new one.
260 * btrfs_alloc_reserved_extent is used to finish the allocation.
261 */ 257 */
262static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, 258static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
263 struct btrfs_root *root, 259 struct btrfs_root *root,
264 struct extent_buffer *buf, 260 struct extent_buffer *buf,
265 struct extent_buffer *parent, int parent_slot, 261 struct extent_buffer *parent, int parent_slot,
266 struct extent_buffer **cow_ret, 262 struct extent_buffer **cow_ret,
267 u64 search_start, u64 empty_size, 263 u64 search_start, u64 empty_size)
268 u64 prealloc_dest)
269{ 264{
270 u64 parent_start; 265 u64 parent_start;
271 struct extent_buffer *cow; 266 struct extent_buffer *cow;
@@ -291,26 +286,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
291 level = btrfs_header_level(buf); 286 level = btrfs_header_level(buf);
292 nritems = btrfs_header_nritems(buf); 287 nritems = btrfs_header_nritems(buf);
293 288
294 if (prealloc_dest) { 289 cow = btrfs_alloc_free_block(trans, root, buf->len,
295 struct btrfs_key ins; 290 parent_start, root->root_key.objectid,
296 291 trans->transid, level,
297 ins.objectid = prealloc_dest; 292 search_start, empty_size);
298 ins.offset = buf->len;
299 ins.type = BTRFS_EXTENT_ITEM_KEY;
300
301 ret = btrfs_alloc_reserved_extent(trans, root, parent_start,
302 root->root_key.objectid,
303 trans->transid, level, &ins);
304 BUG_ON(ret);
305 cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
306 buf->len, level);
307 } else {
308 cow = btrfs_alloc_free_block(trans, root, buf->len,
309 parent_start,
310 root->root_key.objectid,
311 trans->transid, level,
312 search_start, empty_size);
313 }
314 if (IS_ERR(cow)) 293 if (IS_ERR(cow))
315 return PTR_ERR(cow); 294 return PTR_ERR(cow);
316 295
@@ -413,7 +392,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
413noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, 392noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
414 struct btrfs_root *root, struct extent_buffer *buf, 393 struct btrfs_root *root, struct extent_buffer *buf,
415 struct extent_buffer *parent, int parent_slot, 394 struct extent_buffer *parent, int parent_slot,
416 struct extent_buffer **cow_ret, u64 prealloc_dest) 395 struct extent_buffer **cow_ret)
417{ 396{
418 u64 search_start; 397 u64 search_start;
419 int ret; 398 int ret;
@@ -436,7 +415,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
436 btrfs_header_owner(buf) == root->root_key.objectid && 415 btrfs_header_owner(buf) == root->root_key.objectid &&
437 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { 416 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
438 *cow_ret = buf; 417 *cow_ret = buf;
439 WARN_ON(prealloc_dest);
440 return 0; 418 return 0;
441 } 419 }
442 420
@@ -447,8 +425,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
447 btrfs_set_lock_blocking(buf); 425 btrfs_set_lock_blocking(buf);
448 426
449 ret = __btrfs_cow_block(trans, root, buf, parent, 427 ret = __btrfs_cow_block(trans, root, buf, parent,
450 parent_slot, cow_ret, search_start, 0, 428 parent_slot, cow_ret, search_start, 0);
451 prealloc_dest);
452 return ret; 429 return ret;
453} 430}
454 431
@@ -617,7 +594,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
617 err = __btrfs_cow_block(trans, root, cur, parent, i, 594 err = __btrfs_cow_block(trans, root, cur, parent, i,
618 &cur, search_start, 595 &cur, search_start,
619 min(16 * blocksize, 596 min(16 * blocksize,
620 (end_slot - i) * blocksize), 0); 597 (end_slot - i) * blocksize));
621 if (err) { 598 if (err) {
622 btrfs_tree_unlock(cur); 599 btrfs_tree_unlock(cur);
623 free_extent_buffer(cur); 600 free_extent_buffer(cur);
@@ -937,7 +914,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
937 BUG_ON(!child); 914 BUG_ON(!child);
938 btrfs_tree_lock(child); 915 btrfs_tree_lock(child);
939 btrfs_set_lock_blocking(child); 916 btrfs_set_lock_blocking(child);
940 ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0); 917 ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
941 BUG_ON(ret); 918 BUG_ON(ret);
942 919
943 spin_lock(&root->node_lock); 920 spin_lock(&root->node_lock);
@@ -979,7 +956,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
979 btrfs_tree_lock(left); 956 btrfs_tree_lock(left);
980 btrfs_set_lock_blocking(left); 957 btrfs_set_lock_blocking(left);
981 wret = btrfs_cow_block(trans, root, left, 958 wret = btrfs_cow_block(trans, root, left,
982 parent, pslot - 1, &left, 0); 959 parent, pslot - 1, &left);
983 if (wret) { 960 if (wret) {
984 ret = wret; 961 ret = wret;
985 goto enospc; 962 goto enospc;
@@ -990,7 +967,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
990 btrfs_tree_lock(right); 967 btrfs_tree_lock(right);
991 btrfs_set_lock_blocking(right); 968 btrfs_set_lock_blocking(right);
992 wret = btrfs_cow_block(trans, root, right, 969 wret = btrfs_cow_block(trans, root, right,
993 parent, pslot + 1, &right, 0); 970 parent, pslot + 1, &right);
994 if (wret) { 971 if (wret) {
995 ret = wret; 972 ret = wret;
996 goto enospc; 973 goto enospc;
@@ -1171,7 +1148,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
1171 wret = 1; 1148 wret = 1;
1172 } else { 1149 } else {
1173 ret = btrfs_cow_block(trans, root, left, parent, 1150 ret = btrfs_cow_block(trans, root, left, parent,
1174 pslot - 1, &left, 0); 1151 pslot - 1, &left);
1175 if (ret) 1152 if (ret)
1176 wret = 1; 1153 wret = 1;
1177 else { 1154 else {
@@ -1222,7 +1199,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
1222 } else { 1199 } else {
1223 ret = btrfs_cow_block(trans, root, right, 1200 ret = btrfs_cow_block(trans, root, right,
1224 parent, pslot + 1, 1201 parent, pslot + 1,
1225 &right, 0); 1202 &right);
1226 if (ret) 1203 if (ret)
1227 wret = 1; 1204 wret = 1;
1228 else { 1205 else {
@@ -1492,7 +1469,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
1492 u8 lowest_level = 0; 1469 u8 lowest_level = 0;
1493 u64 blocknr; 1470 u64 blocknr;
1494 u64 gen; 1471 u64 gen;
1495 struct btrfs_key prealloc_block;
1496 1472
1497 lowest_level = p->lowest_level; 1473 lowest_level = p->lowest_level;
1498 WARN_ON(lowest_level && ins_len > 0); 1474 WARN_ON(lowest_level && ins_len > 0);
@@ -1501,8 +1477,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
1501 if (ins_len < 0) 1477 if (ins_len < 0)
1502 lowest_unlock = 2; 1478 lowest_unlock = 2;
1503 1479
1504 prealloc_block.objectid = 0;
1505
1506again: 1480again:
1507 if (p->skip_locking) 1481 if (p->skip_locking)
1508 b = btrfs_root_node(root); 1482 b = btrfs_root_node(root);
@@ -1529,44 +1503,11 @@ again:
1529 !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) { 1503 !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) {
1530 goto cow_done; 1504 goto cow_done;
1531 } 1505 }
1532
1533 /* ok, we have to cow, is our old prealloc the right
1534 * size?
1535 */
1536 if (prealloc_block.objectid &&
1537 prealloc_block.offset != b->len) {
1538 btrfs_release_path(root, p);
1539 btrfs_free_reserved_extent(root,
1540 prealloc_block.objectid,
1541 prealloc_block.offset);
1542 prealloc_block.objectid = 0;
1543 goto again;
1544 }
1545
1546 /*
1547 * for higher level blocks, try not to allocate blocks
1548 * with the block and the parent locks held.
1549 */
1550 if (level > 0 && !prealloc_block.objectid) {
1551 u32 size = b->len;
1552 u64 hint = b->start;
1553
1554 btrfs_release_path(root, p);
1555 ret = btrfs_reserve_extent(trans, root,
1556 size, size, 0,
1557 hint, (u64)-1,
1558 &prealloc_block, 0);
1559 BUG_ON(ret);
1560 goto again;
1561 }
1562
1563 btrfs_set_path_blocking(p); 1506 btrfs_set_path_blocking(p);
1564 1507
1565 wret = btrfs_cow_block(trans, root, b, 1508 wret = btrfs_cow_block(trans, root, b,
1566 p->nodes[level + 1], 1509 p->nodes[level + 1],
1567 p->slots[level + 1], 1510 p->slots[level + 1], &b);
1568 &b, prealloc_block.objectid);
1569 prealloc_block.objectid = 0;
1570 if (wret) { 1511 if (wret) {
1571 free_extent_buffer(b); 1512 free_extent_buffer(b);
1572 ret = wret; 1513 ret = wret;
@@ -1743,11 +1684,6 @@ done:
1743 * from here on, so for now just mark it as blocking 1684 * from here on, so for now just mark it as blocking
1744 */ 1685 */
1745 btrfs_set_path_blocking(p); 1686 btrfs_set_path_blocking(p);
1746 if (prealloc_block.objectid) {
1747 btrfs_free_reserved_extent(root,
1748 prealloc_block.objectid,
1749 prealloc_block.offset);
1750 }
1751 return ret; 1687 return ret;
1752} 1688}
1753 1689
@@ -1768,7 +1704,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
1768 int ret; 1704 int ret;
1769 1705
1770 eb = btrfs_lock_root_node(root); 1706 eb = btrfs_lock_root_node(root);
1771 ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb, 0); 1707 ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb);
1772 BUG_ON(ret); 1708 BUG_ON(ret);
1773 1709
1774 btrfs_set_lock_blocking(eb); 1710 btrfs_set_lock_blocking(eb);
@@ -1826,7 +1762,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
1826 } 1762 }
1827 1763
1828 ret = btrfs_cow_block(trans, root, eb, parent, slot, 1764 ret = btrfs_cow_block(trans, root, eb, parent, slot,
1829 &eb, 0); 1765 &eb);
1830 BUG_ON(ret); 1766 BUG_ON(ret);
1831 1767
1832 if (root->root_key.objectid == 1768 if (root->root_key.objectid ==
@@ -2377,7 +2313,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
2377 2313
2378 /* cow and double check */ 2314 /* cow and double check */
2379 ret = btrfs_cow_block(trans, root, right, upper, 2315 ret = btrfs_cow_block(trans, root, right, upper,
2380 slot + 1, &right, 0); 2316 slot + 1, &right);
2381 if (ret) 2317 if (ret)
2382 goto out_unlock; 2318 goto out_unlock;
2383 2319
@@ -2576,7 +2512,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
2576 2512
2577 /* cow and double check */ 2513 /* cow and double check */
2578 ret = btrfs_cow_block(trans, root, left, 2514 ret = btrfs_cow_block(trans, root, left,
2579 path->nodes[1], slot - 1, &left, 0); 2515 path->nodes[1], slot - 1, &left);
2580 if (ret) { 2516 if (ret) {
2581 /* we hit -ENOSPC, but it isn't fatal here */ 2517 /* we hit -ENOSPC, but it isn't fatal here */
2582 ret = 1; 2518 ret = 1;
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 5e1d4e30e9d8..3a37ba7a8d65 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1838,7 +1838,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
1838int btrfs_cow_block(struct btrfs_trans_handle *trans, 1838int btrfs_cow_block(struct btrfs_trans_handle *trans,
1839 struct btrfs_root *root, struct extent_buffer *buf, 1839 struct btrfs_root *root, struct extent_buffer *buf,
1840 struct extent_buffer *parent, int parent_slot, 1840 struct extent_buffer *parent, int parent_slot,
1841 struct extent_buffer **cow_ret, u64 prealloc_dest); 1841 struct extent_buffer **cow_ret);
1842int btrfs_copy_root(struct btrfs_trans_handle *trans, 1842int btrfs_copy_root(struct btrfs_trans_handle *trans,
1843 struct btrfs_root *root, 1843 struct btrfs_root *root,
1844 struct extent_buffer *buf, 1844 struct extent_buffer *buf,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 4112d53d4f4d..d638c54d39e9 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -463,7 +463,7 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
463 btrfs_extent_post_op(trans, fs_info->tree_root); 463 btrfs_extent_post_op(trans, fs_info->tree_root);
464 464
465 eb = btrfs_lock_root_node(fs_info->tree_root); 465 eb = btrfs_lock_root_node(fs_info->tree_root);
466 btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0); 466 btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
467 btrfs_tree_unlock(eb); 467 btrfs_tree_unlock(eb);
468 free_extent_buffer(eb); 468 free_extent_buffer(eb);
469 469
@@ -766,7 +766,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
766 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); 766 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
767 767
768 old = btrfs_lock_root_node(root); 768 old = btrfs_lock_root_node(root);
769 btrfs_cow_block(trans, root, old, NULL, 0, &old, 0); 769 btrfs_cow_block(trans, root, old, NULL, 0, &old);
770 770
771 btrfs_copy_root(trans, root, old, &tmp, objectid); 771 btrfs_copy_root(trans, root, old, &tmp, objectid);
772 btrfs_tree_unlock(old); 772 btrfs_tree_unlock(old);