diff options
author | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 |
commit | b9fab919b748c7b39c19ff236ed6c5682c266dde (patch) | |
tree | 49e5a6f8041a7f0a9be0c1a39cd9088e3faa1df2 /fs/btrfs/ctree.c | |
parent | ea9947b4395fa34666086b2fa6f686e94903e047 (diff) |
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>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 086303b9be64..4106264fbc65 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -725,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
725 | 725 | ||
726 | cur = btrfs_find_tree_block(root, blocknr, blocksize); | 726 | cur = btrfs_find_tree_block(root, blocknr, blocksize); |
727 | if (cur) | 727 | if (cur) |
728 | uptodate = btrfs_buffer_uptodate(cur, gen); | 728 | uptodate = btrfs_buffer_uptodate(cur, gen, 0); |
729 | else | 729 | else |
730 | uptodate = 0; | 730 | uptodate = 0; |
731 | if (!cur || !uptodate) { | 731 | if (!cur || !uptodate) { |
@@ -1360,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1360 | block1 = btrfs_node_blockptr(parent, slot - 1); | 1360 | block1 = btrfs_node_blockptr(parent, slot - 1); |
1361 | gen = btrfs_node_ptr_generation(parent, slot - 1); | 1361 | gen = btrfs_node_ptr_generation(parent, slot - 1); |
1362 | eb = btrfs_find_tree_block(root, block1, blocksize); | 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 | block1 = 0; | 1369 | block1 = 0; |
1365 | free_extent_buffer(eb); | 1370 | free_extent_buffer(eb); |
1366 | } | 1371 | } |
@@ -1368,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1368 | block2 = btrfs_node_blockptr(parent, slot + 1); | 1373 | block2 = btrfs_node_blockptr(parent, slot + 1); |
1369 | gen = btrfs_node_ptr_generation(parent, slot + 1); | 1374 | gen = btrfs_node_ptr_generation(parent, slot + 1); |
1370 | eb = btrfs_find_tree_block(root, block2, blocksize); | 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 | block2 = 0; | 1377 | block2 = 0; |
1373 | free_extent_buffer(eb); | 1378 | free_extent_buffer(eb); |
1374 | } | 1379 | } |
@@ -1506,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1506 | 1511 | ||
1507 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1512 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
1508 | if (tmp) { | 1513 | if (tmp) { |
1509 | if (btrfs_buffer_uptodate(tmp, 0)) { | 1514 | /* first we do an atomic uptodate check */ |
1510 | if (btrfs_buffer_uptodate(tmp, gen)) { | 1515 | if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) { |
1516 | if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) { | ||
1511 | /* | 1517 | /* |
1512 | * we found an up to date block without | 1518 | * we found an up to date block without |
1513 | * sleeping, return | 1519 | * sleeping, return |
@@ -1525,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1525 | free_extent_buffer(tmp); | 1531 | free_extent_buffer(tmp); |
1526 | btrfs_set_path_blocking(p); | 1532 | btrfs_set_path_blocking(p); |
1527 | 1533 | ||
1534 | /* now we're allowed to do a blocking uptodate check */ | ||
1528 | tmp = read_tree_block(root, blocknr, blocksize, gen); | 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 | *eb_ret = tmp; | 1537 | *eb_ret = tmp; |
1531 | return 0; | 1538 | return 0; |
1532 | } | 1539 | } |
@@ -1561,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1561 | * and give up so that our caller doesn't loop forever | 1568 | * and give up so that our caller doesn't loop forever |
1562 | * on our EAGAINs. | 1569 | * on our EAGAINs. |
1563 | */ | 1570 | */ |
1564 | if (!btrfs_buffer_uptodate(tmp, 0)) | 1571 | if (!btrfs_buffer_uptodate(tmp, 0, 0)) |
1565 | ret = -EIO; | 1572 | ret = -EIO; |
1566 | free_extent_buffer(tmp); | 1573 | free_extent_buffer(tmp); |
1567 | } | 1574 | } |
@@ -4045,7 +4052,7 @@ again: | |||
4045 | tmp = btrfs_find_tree_block(root, blockptr, | 4052 | tmp = btrfs_find_tree_block(root, blockptr, |
4046 | btrfs_level_size(root, level - 1)); | 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 | free_extent_buffer(tmp); | 4056 | free_extent_buffer(tmp); |
4050 | break; | 4057 | break; |
4051 | } | 4058 | } |
@@ -4168,7 +4175,8 @@ next: | |||
4168 | struct extent_buffer *cur; | 4175 | struct extent_buffer *cur; |
4169 | cur = btrfs_find_tree_block(root, blockptr, | 4176 | cur = btrfs_find_tree_block(root, blockptr, |
4170 | btrfs_level_size(root, level - 1)); | 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 | slot++; | 4180 | slot++; |
4173 | if (cur) | 4181 | if (cur) |
4174 | free_extent_buffer(cur); | 4182 | free_extent_buffer(cur); |