Commit b9fab919 authored by Chris Mason's avatar Chris Mason

Btrfs: avoid sleeping in verify_parent_transid while atomic

verify_parent_transid needs to lock the extent range to make
sure no IO is underway, and so it can safely clear the
uptodate bits if our checks fail.

But, a few callers are using it with spinlocks held.  Most
of the time, the generation numbers are going to match, and
we don't want to switch to a blocking lock just for the error
case.  This adds an atomic flag to verify_parent_transid,
and changes it to return EAGAIN if it needs to block to
properly verifiy things.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent ea9947b4
...@@ -725,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -725,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
cur = btrfs_find_tree_block(root, blocknr, blocksize); cur = btrfs_find_tree_block(root, blocknr, blocksize);
if (cur) if (cur)
uptodate = btrfs_buffer_uptodate(cur, gen); uptodate = btrfs_buffer_uptodate(cur, gen, 0);
else else
uptodate = 0; uptodate = 0;
if (!cur || !uptodate) { if (!cur || !uptodate) {
...@@ -1360,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root, ...@@ -1360,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root,
block1 = btrfs_node_blockptr(parent, slot - 1); block1 = btrfs_node_blockptr(parent, slot - 1);
gen = btrfs_node_ptr_generation(parent, slot - 1); gen = btrfs_node_ptr_generation(parent, slot - 1);
eb = btrfs_find_tree_block(root, block1, blocksize); eb = btrfs_find_tree_block(root, block1, blocksize);
if (eb && btrfs_buffer_uptodate(eb, gen)) /*
* if we get -eagain from btrfs_buffer_uptodate, we
* don't want to return eagain here. That will loop
* forever
*/
if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
block1 = 0; block1 = 0;
free_extent_buffer(eb); free_extent_buffer(eb);
} }
...@@ -1368,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, ...@@ -1368,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root,
block2 = btrfs_node_blockptr(parent, slot + 1); block2 = btrfs_node_blockptr(parent, slot + 1);
gen = btrfs_node_ptr_generation(parent, slot + 1); gen = btrfs_node_ptr_generation(parent, slot + 1);
eb = btrfs_find_tree_block(root, block2, blocksize); eb = btrfs_find_tree_block(root, block2, blocksize);
if (eb && btrfs_buffer_uptodate(eb, gen)) if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
block2 = 0; block2 = 0;
free_extent_buffer(eb); free_extent_buffer(eb);
} }
...@@ -1506,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, ...@@ -1506,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
tmp = btrfs_find_tree_block(root, blocknr, blocksize); tmp = btrfs_find_tree_block(root, blocknr, blocksize);
if (tmp) { if (tmp) {
if (btrfs_buffer_uptodate(tmp, 0)) { /* first we do an atomic uptodate check */
if (btrfs_buffer_uptodate(tmp, gen)) { if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) {
if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
/* /*
* we found an up to date block without * we found an up to date block without
* sleeping, return * sleeping, return
...@@ -1525,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, ...@@ -1525,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
free_extent_buffer(tmp); free_extent_buffer(tmp);
btrfs_set_path_blocking(p); btrfs_set_path_blocking(p);
/* now we're allowed to do a blocking uptodate check */
tmp = read_tree_block(root, blocknr, blocksize, gen); tmp = read_tree_block(root, blocknr, blocksize, gen);
if (tmp && btrfs_buffer_uptodate(tmp, gen)) { if (tmp && btrfs_buffer_uptodate(tmp, gen, 0) > 0) {
*eb_ret = tmp; *eb_ret = tmp;
return 0; return 0;
} }
...@@ -1561,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, ...@@ -1561,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
* and give up so that our caller doesn't loop forever * and give up so that our caller doesn't loop forever
* on our EAGAINs. * on our EAGAINs.
*/ */
if (!btrfs_buffer_uptodate(tmp, 0)) if (!btrfs_buffer_uptodate(tmp, 0, 0))
ret = -EIO; ret = -EIO;
free_extent_buffer(tmp); free_extent_buffer(tmp);
} }
...@@ -4045,7 +4052,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -4045,7 +4052,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
tmp = btrfs_find_tree_block(root, blockptr, tmp = btrfs_find_tree_block(root, blockptr,
btrfs_level_size(root, level - 1)); btrfs_level_size(root, level - 1));
if (tmp && btrfs_buffer_uptodate(tmp, gen)) { if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
free_extent_buffer(tmp); free_extent_buffer(tmp);
break; break;
} }
...@@ -4168,7 +4175,8 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, ...@@ -4168,7 +4175,8 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
struct extent_buffer *cur; struct extent_buffer *cur;
cur = btrfs_find_tree_block(root, blockptr, cur = btrfs_find_tree_block(root, blockptr,
btrfs_level_size(root, level - 1)); btrfs_level_size(root, level - 1));
if (!cur || !btrfs_buffer_uptodate(cur, gen)) { if (!cur ||
btrfs_buffer_uptodate(cur, gen, 1) <= 0) {
slot++; slot++;
if (cur) if (cur)
free_extent_buffer(cur); free_extent_buffer(cur);
......
...@@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, ...@@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
* in the wrong place. * in the wrong place.
*/ */
static int verify_parent_transid(struct extent_io_tree *io_tree, static int verify_parent_transid(struct extent_io_tree *io_tree,
struct extent_buffer *eb, u64 parent_transid) struct extent_buffer *eb, u64 parent_transid,
int atomic)
{ {
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
int ret; int ret;
...@@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, ...@@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
if (!parent_transid || btrfs_header_generation(eb) == parent_transid) if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
return 0; return 0;
if (atomic)
return -EAGAIN;
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
0, &cached_state); 0, &cached_state);
if (extent_buffer_uptodate(eb) && if (extent_buffer_uptodate(eb) &&
...@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, ...@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
ret = read_extent_buffer_pages(io_tree, eb, start, ret = read_extent_buffer_pages(io_tree, eb, start,
WAIT_COMPLETE, WAIT_COMPLETE,
btree_get_extent, mirror_num); btree_get_extent, mirror_num);
if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) if (!ret && !verify_parent_transid(io_tree, eb,
parent_transid, 0))
break; break;
/* /*
...@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root, ...@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
root->commit_root = NULL; root->commit_root = NULL;
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation); blocksize, generation);
if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {
free_extent_buffer(root->node); free_extent_buffer(root->node);
root->node = NULL; root->node = NULL;
return -EIO; return -EIO;
...@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root) ...@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root)
return 0; return 0;
} }
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic)
{ {
int ret; int ret;
struct inode *btree_inode = buf->pages[0]->mapping->host; struct inode *btree_inode = buf->pages[0]->mapping->host;
...@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) ...@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
return ret; return ret;
ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf,
parent_transid); parent_transid, atomic);
if (ret == -EAGAIN)
return ret;
return !ret; return !ret;
} }
......
...@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); ...@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf); void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic);
int btrfs_set_buffer_uptodate(struct extent_buffer *buf); int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
......
...@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, ...@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
goto skip; goto skip;
} }
if (!btrfs_buffer_uptodate(next, generation)) { if (!btrfs_buffer_uptodate(next, generation, 0)) {
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
free_extent_buffer(next); free_extent_buffer(next);
next = NULL; next = NULL;
......
...@@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log, ...@@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log,
log->fs_info->extent_root, log->fs_info->extent_root,
eb->start, eb->len); eb->start, eb->len);
if (btrfs_buffer_uptodate(eb, gen)) { if (btrfs_buffer_uptodate(eb, gen, 0)) {
if (wc->write) if (wc->write)
btrfs_write_tree_block(eb); btrfs_write_tree_block(eb);
if (wc->wait) if (wc->wait)
......
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