Skip to content

Commit b9fab91

Browse files
committed
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 <[email protected]>
1 parent ea9947b commit b9fab91

File tree

5 files changed

+34
-17
lines changed

5 files changed

+34
-17
lines changed

fs/btrfs/ctree.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
725725

726726
cur = btrfs_find_tree_block(root, blocknr, blocksize);
727727
if (cur)
728-
uptodate = btrfs_buffer_uptodate(cur, gen);
728+
uptodate = btrfs_buffer_uptodate(cur, gen, 0);
729729
else
730730
uptodate = 0;
731731
if (!cur || !uptodate) {
@@ -1360,15 +1360,20 @@ static noinline int reada_for_balance(struct btrfs_root *root,
13601360
block1 = btrfs_node_blockptr(parent, slot - 1);
13611361
gen = btrfs_node_ptr_generation(parent, slot - 1);
13621362
eb = btrfs_find_tree_block(root, block1, blocksize);
1363-
if (eb && btrfs_buffer_uptodate(eb, gen))
1363+
/*
1364+
* if we get -eagain from btrfs_buffer_uptodate, we
1365+
* don't want to return eagain here. That will loop
1366+
* forever
1367+
*/
1368+
if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
13641369
block1 = 0;
13651370
free_extent_buffer(eb);
13661371
}
13671372
if (slot + 1 < nritems) {
13681373
block2 = btrfs_node_blockptr(parent, slot + 1);
13691374
gen = btrfs_node_ptr_generation(parent, slot + 1);
13701375
eb = btrfs_find_tree_block(root, block2, blocksize);
1371-
if (eb && btrfs_buffer_uptodate(eb, gen))
1376+
if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
13721377
block2 = 0;
13731378
free_extent_buffer(eb);
13741379
}
@@ -1506,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
15061511

15071512
tmp = btrfs_find_tree_block(root, blocknr, blocksize);
15081513
if (tmp) {
1509-
if (btrfs_buffer_uptodate(tmp, 0)) {
1510-
if (btrfs_buffer_uptodate(tmp, gen)) {
1514+
/* first we do an atomic uptodate check */
1515+
if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) {
1516+
if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
15111517
/*
15121518
* we found an up to date block without
15131519
* sleeping, return
@@ -1525,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
15251531
free_extent_buffer(tmp);
15261532
btrfs_set_path_blocking(p);
15271533

1534+
/* now we're allowed to do a blocking uptodate check */
15281535
tmp = read_tree_block(root, blocknr, blocksize, gen);
1529-
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
1536+
if (tmp && btrfs_buffer_uptodate(tmp, gen, 0) > 0) {
15301537
*eb_ret = tmp;
15311538
return 0;
15321539
}
@@ -1561,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
15611568
* and give up so that our caller doesn't loop forever
15621569
* on our EAGAINs.
15631570
*/
1564-
if (!btrfs_buffer_uptodate(tmp, 0))
1571+
if (!btrfs_buffer_uptodate(tmp, 0, 0))
15651572
ret = -EIO;
15661573
free_extent_buffer(tmp);
15671574
}
@@ -4045,7 +4052,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
40454052
tmp = btrfs_find_tree_block(root, blockptr,
40464053
btrfs_level_size(root, level - 1));
40474054

4048-
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
4055+
if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
40494056
free_extent_buffer(tmp);
40504057
break;
40514058
}
@@ -4168,7 +4175,8 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
41684175
struct extent_buffer *cur;
41694176
cur = btrfs_find_tree_block(root, blockptr,
41704177
btrfs_level_size(root, level - 1));
4171-
if (!cur || !btrfs_buffer_uptodate(cur, gen)) {
4178+
if (!cur ||
4179+
btrfs_buffer_uptodate(cur, gen, 1) <= 0) {
41724180
slot++;
41734181
if (cur)
41744182
free_extent_buffer(cur);

fs/btrfs/disk-io.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,18 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
323323
* in the wrong place.
324324
*/
325325
static int verify_parent_transid(struct extent_io_tree *io_tree,
326-
struct extent_buffer *eb, u64 parent_transid)
326+
struct extent_buffer *eb, u64 parent_transid,
327+
int atomic)
327328
{
328329
struct extent_state *cached_state = NULL;
329330
int ret;
330331

331332
if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
332333
return 0;
333334

335+
if (atomic)
336+
return -EAGAIN;
337+
334338
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
335339
0, &cached_state);
336340
if (extent_buffer_uptodate(eb) &&
@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
372376
ret = read_extent_buffer_pages(io_tree, eb, start,
373377
WAIT_COMPLETE,
374378
btree_get_extent, mirror_num);
375-
if (!ret && !verify_parent_transid(io_tree, eb, parent_transid))
379+
if (!ret && !verify_parent_transid(io_tree, eb,
380+
parent_transid, 0))
376381
break;
377382

378383
/*
@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
12021207
root->commit_root = NULL;
12031208
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
12041209
blocksize, generation);
1205-
if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
1210+
if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {
12061211
free_extent_buffer(root->node);
12071212
root->node = NULL;
12081213
return -EIO;
@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root)
31433148
return 0;
31443149
}
31453150

3146-
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
3151+
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
3152+
int atomic)
31473153
{
31483154
int ret;
31493155
struct inode *btree_inode = buf->pages[0]->mapping->host;
@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
31533159
return ret;
31543160

31553161
ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf,
3156-
parent_transid);
3162+
parent_transid, atomic);
3163+
if (ret == -EAGAIN)
3164+
return ret;
31573165
return !ret;
31583166
}
31593167

fs/btrfs/disk-io.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
6666
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
6767
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
6868
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
69-
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
69+
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
70+
int atomic);
7071
int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
7172
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
7273
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
65686568
goto skip;
65696569
}
65706570

6571-
if (!btrfs_buffer_uptodate(next, generation)) {
6571+
if (!btrfs_buffer_uptodate(next, generation, 0)) {
65726572
btrfs_tree_unlock(next);
65736573
free_extent_buffer(next);
65746574
next = NULL;

fs/btrfs/tree-log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log,
279279
log->fs_info->extent_root,
280280
eb->start, eb->len);
281281

282-
if (btrfs_buffer_uptodate(eb, gen)) {
282+
if (btrfs_buffer_uptodate(eb, gen, 0)) {
283283
if (wc->write)
284284
btrfs_write_tree_block(eb);
285285
if (wc->wait)

0 commit comments

Comments
 (0)