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: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
ea9947b439
commit
b9fab919b7
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
* 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 @@ again:
|
||||||
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 @@ next:
|
||||||
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,
|
||||||
* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue