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.
Unified · Split
| @@ -725,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, · 724 unmodified lines | ||
| 725 | 725 | |
| 726 | 726 | cur = btrfs_find_tree_block(root, blocknr, blocksize); |
| 727 | 727 | if (cur) |
| 728 | − uptodate = btrfs_buffer_uptodate(cur, gen); | |
| 728 | + uptodate = btrfs_buffer_uptodate(cur, gen, 0); | |
| 729 | 729 | else |
| 730 | 730 | uptodate = 0; |
| 731 | 731 | if (!cur || !uptodate) { |
| @@ -1360,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root, · 628 unmodified lines | ||
| 1360 | 1360 | block1 = btrfs_node_blockptr(parent, slot - 1); |
| 1361 | 1361 | gen = btrfs_node_ptr_generation(parent, slot - 1); |
| 1362 | 1362 | 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) | |
| 1364 | 1369 | block1 = 0; |
| 1365 | 1370 | free_extent_buffer(eb); |
| 1366 | 1371 | } |
| @@ -1368,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, · 1 unmodified line | ||
| 1368 | 1373 | block2 = btrfs_node_blockptr(parent, slot + 1); |
| 1369 | 1374 | gen = btrfs_node_ptr_generation(parent, slot + 1); |
| 1370 | 1375 | 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) | |
| 1372 | 1377 | block2 = 0; |
| 1373 | 1378 | free_extent_buffer(eb); |
| 1374 | 1379 | } |
| @@ -1506,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, · 131 unmodified lines | ||
| 1506 | 1511 | |
| 1507 | 1512 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
| 1508 | 1513 | 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) { | |
| 1511 | 1517 | /* |
| 1512 | 1518 | * we found an up to date block without |
| 1513 | 1519 | * sleeping, return |
| @@ -1525,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, · 11 unmodified lines | ||
| 1525 | 1531 | free_extent_buffer(tmp); |
| 1526 | 1532 | btrfs_set_path_blocking(p); |
| 1527 | 1533 | |
| 1534 | + /* now we're allowed to do a blocking uptodate check */ | |
| 1528 | 1535 | 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) { | |
| 1530 | 1537 | *eb_ret = tmp; |
| 1531 | 1538 | return 0; |
| 1532 | 1539 | } |
| @@ -1561,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, · 28 unmodified lines | ||
| 1561 | 1568 | * and give up so that our caller doesn't loop forever |
| 1562 | 1569 | * on our EAGAINs. |
| 1563 | 1570 | */ |
| 1564 | − if (!btrfs_buffer_uptodate(tmp, 0)) | |
| 1571 | + if (!btrfs_buffer_uptodate(tmp, 0, 0)) | |
| 1565 | 1572 | ret = -EIO; |
| 1566 | 1573 | free_extent_buffer(tmp); |
| 1567 | 1574 | } |
| @@ -4045,7 +4052,7 @@ again: · 2477 unmodified lines | ||
| 4045 | 4052 | tmp = btrfs_find_tree_block(root, blockptr, |
| 4046 | 4053 | btrfs_level_size(root, level - 1)); |
| 4047 | 4054 | |
| 4048 | − if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | |
| 4055 | + if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) { | |
| 4049 | 4056 | free_extent_buffer(tmp); |
| 4050 | 4057 | break; |
| 4051 | 4058 | } |
| @@ -4168,7 +4175,8 @@ next: · 116 unmodified lines | ||
| 4168 | 4175 | struct extent_buffer *cur; |
| 4169 | 4176 | cur = btrfs_find_tree_block(root, blockptr, |
| 4170 | 4177 | 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) { | |
| 4172 | 4180 | slot++; |
| 4173 | 4181 | if (cur) |
| 4174 | 4182 | free_extent_buffer(cur); |
| @@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, · 322 unmodified lines | ||
| 323 | 323 | * in the wrong place. |
| 324 | 324 | */ |
| 325 | 325 | 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) | |
| 327 | 328 | { |
| 328 | 329 | struct extent_state *cached_state = NULL; |
| 329 | 330 | int ret; |
| @@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, · 1 unmodified line | ||
| 331 | 332 | if (!parent_transid || btrfs_header_generation(eb) == parent_transid) |
| 332 | 333 | return 0; |
| 333 | 334 | |
| 335 | + if (atomic) | |
| 336 | + return -EAGAIN; | |
| 337 | + | |
| 334 | 338 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, |
| 335 | 339 | 0, &cached_state); |
| 336 | 340 | if (extent_buffer_uptodate(eb) && |
| @@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, · 35 unmodified lines | ||
| 372 | 376 | ret = read_extent_buffer_pages(io_tree, eb, start, |
| 373 | 377 | WAIT_COMPLETE, |
| 374 | 378 | 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)) | |
| 376 | 381 | break; |
| 377 | 382 | |
| 378 | 383 | /* |
| @@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root, · 823 unmodified lines | ||
| 1202 | 1207 | root->commit_root = NULL; |
| 1203 | 1208 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
| 1204 | 1209 | blocksize, generation); |
| 1205 | − if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { | |
| 1210 | + if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) { | |
| 1206 | 1211 | free_extent_buffer(root->node); |
| 1207 | 1212 | root->node = NULL; |
| 1208 | 1213 | return -EIO; |
| @@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root) · 1934 unmodified lines | ||
| 3143 | 3148 | return 0; |
| 3144 | 3149 | } |
| 3145 | 3150 | |
| 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) | |
| 3147 | 3153 | { |
| 3148 | 3154 | int ret; |
| 3149 | 3155 | struct inode *btree_inode = buf->pages[0]->mapping->host; |
| @@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) · 3 unmodified lines | ||
| 3153 | 3159 | return ret; |
| 3154 | 3160 | |
| 3155 | 3161 | 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; | |
| 3157 | 3165 | return !ret; |
| 3158 | 3166 | } |
| 3159 | 3167 | |
| @@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); · 65 unmodified lines | ||
| 66 | 66 | void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); |
| 67 | 67 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); |
| 68 | 68 | 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); | |
| 70 | 71 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf); |
| 71 | 72 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); |
| 72 | 73 | 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, · 6567 unmodified lines | ||
| 6568 | 6568 | goto skip; |
| 6569 | 6569 | } |
| 6570 | 6570 | |
| 6571 | − if (!btrfs_buffer_uptodate(next, generation)) { | |
| 6571 | + if (!btrfs_buffer_uptodate(next, generation, 0)) { | |
| 6572 | 6572 | btrfs_tree_unlock(next); |
| 6573 | 6573 | free_extent_buffer(next); |
| 6574 | 6574 | next = NULL; |
| @@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log, · 278 unmodified lines | ||
| 279 | 279 | log->fs_info->extent_root, |
| 280 | 280 | eb->start, eb->len); |
| 281 | 281 | |
| 282 | − if (btrfs_buffer_uptodate(eb, gen)) { | |
| 282 | + if (btrfs_buffer_uptodate(eb, gen, 0)) { | |
| 283 | 283 | if (wc->write) |
| 284 | 284 | btrfs_write_tree_block(eb); |
| 285 | 285 | if (wc->wait) |