Commit 9fa8cfe7 authored by Chris Mason's avatar Chris Mason

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: default avatarChris Mason <chris.mason@oracle.com>
parent 8e0ee43b
...@@ -254,18 +254,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -254,18 +254,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
* empty_size -- a hint that you plan on doing more cow. This is the size in * empty_size -- a hint that you plan on doing more cow. This is the size in
* bytes the allocator should try to find free next to the block it returns. * bytes the allocator should try to find free next to the block it returns.
* This is just a hint and may be ignored by the allocator. * This is just a hint and may be ignored by the allocator.
*
* prealloc_dest -- if you have already reserved a destination for the cow,
* this uses that block instead of allocating a new one.
* btrfs_alloc_reserved_extent is used to finish the allocation.
*/ */
static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
struct extent_buffer **cow_ret, struct extent_buffer **cow_ret,
u64 search_start, u64 empty_size, u64 search_start, u64 empty_size)
u64 prealloc_dest)
{ {
u64 parent_start; u64 parent_start;
struct extent_buffer *cow; struct extent_buffer *cow;
...@@ -291,26 +286,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -291,26 +286,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
nritems = btrfs_header_nritems(buf); nritems = btrfs_header_nritems(buf);
if (prealloc_dest) { cow = btrfs_alloc_free_block(trans, root, buf->len,
struct btrfs_key ins; parent_start, root->root_key.objectid,
trans->transid, level,
ins.objectid = prealloc_dest; search_start, empty_size);
ins.offset = buf->len;
ins.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_alloc_reserved_extent(trans, root, parent_start,
root->root_key.objectid,
trans->transid, level, &ins);
BUG_ON(ret);
cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
buf->len, level);
} else {
cow = btrfs_alloc_free_block(trans, root, buf->len,
parent_start,
root->root_key.objectid,
trans->transid, level,
search_start, empty_size);
}
if (IS_ERR(cow)) if (IS_ERR(cow))
return PTR_ERR(cow); return PTR_ERR(cow);
...@@ -413,7 +392,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -413,7 +392,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
struct extent_buffer **cow_ret, u64 prealloc_dest) struct extent_buffer **cow_ret)
{ {
u64 search_start; u64 search_start;
int ret; int ret;
...@@ -436,7 +415,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -436,7 +415,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_header_owner(buf) == root->root_key.objectid && btrfs_header_owner(buf) == root->root_key.objectid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
*cow_ret = buf; *cow_ret = buf;
WARN_ON(prealloc_dest);
return 0; return 0;
} }
...@@ -447,8 +425,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -447,8 +425,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_set_lock_blocking(buf); btrfs_set_lock_blocking(buf);
ret = __btrfs_cow_block(trans, root, buf, parent, ret = __btrfs_cow_block(trans, root, buf, parent,
parent_slot, cow_ret, search_start, 0, parent_slot, cow_ret, search_start, 0);
prealloc_dest);
return ret; return ret;
} }
...@@ -617,7 +594,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -617,7 +594,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
err = __btrfs_cow_block(trans, root, cur, parent, i, err = __btrfs_cow_block(trans, root, cur, parent, i,
&cur, search_start, &cur, search_start,
min(16 * blocksize, min(16 * blocksize,
(end_slot - i) * blocksize), 0); (end_slot - i) * blocksize));
if (err) { if (err) {
btrfs_tree_unlock(cur); btrfs_tree_unlock(cur);
free_extent_buffer(cur); free_extent_buffer(cur);
...@@ -937,7 +914,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -937,7 +914,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
BUG_ON(!child); BUG_ON(!child);
btrfs_tree_lock(child); btrfs_tree_lock(child);
btrfs_set_lock_blocking(child); btrfs_set_lock_blocking(child);
ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0); ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
BUG_ON(ret); BUG_ON(ret);
spin_lock(&root->node_lock); spin_lock(&root->node_lock);
...@@ -979,7 +956,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -979,7 +956,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
btrfs_tree_lock(left); btrfs_tree_lock(left);
btrfs_set_lock_blocking(left); btrfs_set_lock_blocking(left);
wret = btrfs_cow_block(trans, root, left, wret = btrfs_cow_block(trans, root, left,
parent, pslot - 1, &left, 0); parent, pslot - 1, &left);
if (wret) { if (wret) {
ret = wret; ret = wret;
goto enospc; goto enospc;
...@@ -990,7 +967,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -990,7 +967,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
btrfs_tree_lock(right); btrfs_tree_lock(right);
btrfs_set_lock_blocking(right); btrfs_set_lock_blocking(right);
wret = btrfs_cow_block(trans, root, right, wret = btrfs_cow_block(trans, root, right,
parent, pslot + 1, &right, 0); parent, pslot + 1, &right);
if (wret) { if (wret) {
ret = wret; ret = wret;
goto enospc; goto enospc;
...@@ -1171,7 +1148,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1171,7 +1148,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
wret = 1; wret = 1;
} else { } else {
ret = btrfs_cow_block(trans, root, left, parent, ret = btrfs_cow_block(trans, root, left, parent,
pslot - 1, &left, 0); pslot - 1, &left);
if (ret) if (ret)
wret = 1; wret = 1;
else { else {
...@@ -1222,7 +1199,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1222,7 +1199,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
} else { } else {
ret = btrfs_cow_block(trans, root, right, ret = btrfs_cow_block(trans, root, right,
parent, pslot + 1, parent, pslot + 1,
&right, 0); &right);
if (ret) if (ret)
wret = 1; wret = 1;
else { else {
...@@ -1492,7 +1469,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1492,7 +1469,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
u8 lowest_level = 0; u8 lowest_level = 0;
u64 blocknr; u64 blocknr;
u64 gen; u64 gen;
struct btrfs_key prealloc_block;
lowest_level = p->lowest_level; lowest_level = p->lowest_level;
WARN_ON(lowest_level && ins_len > 0); WARN_ON(lowest_level && ins_len > 0);
...@@ -1501,8 +1477,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1501,8 +1477,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
if (ins_len < 0) if (ins_len < 0)
lowest_unlock = 2; lowest_unlock = 2;
prealloc_block.objectid = 0;
again: again:
if (p->skip_locking) if (p->skip_locking)
b = btrfs_root_node(root); b = btrfs_root_node(root);
...@@ -1529,44 +1503,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1529,44 +1503,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
!btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) { !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) {
goto cow_done; goto cow_done;
} }
/* ok, we have to cow, is our old prealloc the right
* size?
*/
if (prealloc_block.objectid &&
prealloc_block.offset != b->len) {
btrfs_release_path(root, p);
btrfs_free_reserved_extent(root,
prealloc_block.objectid,
prealloc_block.offset);
prealloc_block.objectid = 0;
goto again;
}
/*
* for higher level blocks, try not to allocate blocks
* with the block and the parent locks held.
*/
if (level > 0 && !prealloc_block.objectid) {
u32 size = b->len;
u64 hint = b->start;
btrfs_release_path(root, p);
ret = btrfs_reserve_extent(trans, root,
size, size, 0,
hint, (u64)-1,
&prealloc_block, 0);
BUG_ON(ret);
goto again;
}
btrfs_set_path_blocking(p); btrfs_set_path_blocking(p);
wret = btrfs_cow_block(trans, root, b, wret = btrfs_cow_block(trans, root, b,
p->nodes[level + 1], p->nodes[level + 1],
p->slots[level + 1], p->slots[level + 1], &b);
&b, prealloc_block.objectid);
prealloc_block.objectid = 0;
if (wret) { if (wret) {
free_extent_buffer(b); free_extent_buffer(b);
ret = wret; ret = wret;
...@@ -1743,11 +1684,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1743,11 +1684,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
* from here on, so for now just mark it as blocking * from here on, so for now just mark it as blocking
*/ */
btrfs_set_path_blocking(p); btrfs_set_path_blocking(p);
if (prealloc_block.objectid) {
btrfs_free_reserved_extent(root,
prealloc_block.objectid,
prealloc_block.offset);
}
return ret; return ret;
} }
...@@ -1768,7 +1704,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans, ...@@ -1768,7 +1704,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
int ret; int ret;
eb = btrfs_lock_root_node(root); eb = btrfs_lock_root_node(root);
ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb, 0); ret = btrfs_cow_block(trans, root, eb, NULL, 0, &eb);
BUG_ON(ret); BUG_ON(ret);
btrfs_set_lock_blocking(eb); btrfs_set_lock_blocking(eb);
...@@ -1826,7 +1762,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans, ...@@ -1826,7 +1762,7 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
} }
ret = btrfs_cow_block(trans, root, eb, parent, slot, ret = btrfs_cow_block(trans, root, eb, parent, slot,
&eb, 0); &eb);
BUG_ON(ret); BUG_ON(ret);
if (root->root_key.objectid == if (root->root_key.objectid ==
...@@ -2377,7 +2313,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2377,7 +2313,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
/* cow and double check */ /* cow and double check */
ret = btrfs_cow_block(trans, root, right, upper, ret = btrfs_cow_block(trans, root, right, upper,
slot + 1, &right, 0); slot + 1, &right);
if (ret) if (ret)
goto out_unlock; goto out_unlock;
...@@ -2576,7 +2512,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2576,7 +2512,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
/* cow and double check */ /* cow and double check */
ret = btrfs_cow_block(trans, root, left, ret = btrfs_cow_block(trans, root, left,
path->nodes[1], slot - 1, &left, 0); path->nodes[1], slot - 1, &left);
if (ret) { if (ret) {
/* we hit -ENOSPC, but it isn't fatal here */ /* we hit -ENOSPC, but it isn't fatal here */
ret = 1; ret = 1;
......
...@@ -1838,7 +1838,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -1838,7 +1838,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
int btrfs_cow_block(struct btrfs_trans_handle *trans, int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
struct extent_buffer **cow_ret, u64 prealloc_dest); struct extent_buffer **cow_ret);
int btrfs_copy_root(struct btrfs_trans_handle *trans, int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf, struct extent_buffer *buf,
......
...@@ -463,7 +463,7 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, ...@@ -463,7 +463,7 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
btrfs_extent_post_op(trans, fs_info->tree_root); btrfs_extent_post_op(trans, fs_info->tree_root);
eb = btrfs_lock_root_node(fs_info->tree_root); eb = btrfs_lock_root_node(fs_info->tree_root);
btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0); btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
btrfs_tree_unlock(eb); btrfs_tree_unlock(eb);
free_extent_buffer(eb); free_extent_buffer(eb);
...@@ -766,7 +766,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -766,7 +766,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
old = btrfs_lock_root_node(root); old = btrfs_lock_root_node(root);
btrfs_cow_block(trans, root, old, NULL, 0, &old, 0); btrfs_cow_block(trans, root, old, NULL, 0, &old);
btrfs_copy_root(trans, root, old, &tmp, objectid); btrfs_copy_root(trans, root, old, &tmp, objectid);
btrfs_tree_unlock(old); btrfs_tree_unlock(old);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment