diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
| -rw-r--r-- | fs/btrfs/ctree.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index a99f1c2a710d..fedf8b9f03a2 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -1469,6 +1469,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1469 | u32 blocksize; | 1469 | u32 blocksize; |
| 1470 | struct extent_buffer *b = *eb_ret; | 1470 | struct extent_buffer *b = *eb_ret; |
| 1471 | struct extent_buffer *tmp; | 1471 | struct extent_buffer *tmp; |
| 1472 | int ret; | ||
| 1472 | 1473 | ||
| 1473 | blocknr = btrfs_node_blockptr(b, slot); | 1474 | blocknr = btrfs_node_blockptr(b, slot); |
| 1474 | gen = btrfs_node_ptr_generation(b, slot); | 1475 | gen = btrfs_node_ptr_generation(b, slot); |
| @@ -1476,6 +1477,10 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1476 | 1477 | ||
| 1477 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1478 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
| 1478 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | 1479 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { |
| 1480 | /* | ||
| 1481 | * we found an up to date block without sleeping, return | ||
| 1482 | * right away | ||
| 1483 | */ | ||
| 1479 | *eb_ret = tmp; | 1484 | *eb_ret = tmp; |
| 1480 | return 0; | 1485 | return 0; |
| 1481 | } | 1486 | } |
| @@ -1483,7 +1488,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1483 | /* | 1488 | /* |
| 1484 | * reduce lock contention at high levels | 1489 | * reduce lock contention at high levels |
| 1485 | * of the btree by dropping locks before | 1490 | * of the btree by dropping locks before |
| 1486 | * we read. | 1491 | * we read. Don't release the lock on the current |
| 1492 | * level because we need to walk this node to figure | ||
| 1493 | * out which blocks to read. | ||
| 1487 | */ | 1494 | */ |
| 1488 | btrfs_unlock_up_safe(p, level + 1); | 1495 | btrfs_unlock_up_safe(p, level + 1); |
| 1489 | btrfs_set_path_blocking(p); | 1496 | btrfs_set_path_blocking(p); |
| @@ -1494,10 +1501,21 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1494 | reada_for_search(root, p, level, slot, key->objectid); | 1501 | reada_for_search(root, p, level, slot, key->objectid); |
| 1495 | 1502 | ||
| 1496 | btrfs_release_path(NULL, p); | 1503 | btrfs_release_path(NULL, p); |
| 1504 | |||
| 1505 | ret = -EAGAIN; | ||
| 1497 | tmp = read_tree_block(root, blocknr, blocksize, gen); | 1506 | tmp = read_tree_block(root, blocknr, blocksize, gen); |
| 1498 | if (tmp) | 1507 | if (tmp) { |
| 1508 | /* | ||
| 1509 | * If the read above didn't mark this buffer up to date, | ||
| 1510 | * it will never end up being up to date. Set ret to EIO now | ||
| 1511 | * and give up so that our caller doesn't loop forever | ||
| 1512 | * on our EAGAINs. | ||
| 1513 | */ | ||
| 1514 | if (!btrfs_buffer_uptodate(tmp, 0)) | ||
| 1515 | ret = -EIO; | ||
| 1499 | free_extent_buffer(tmp); | 1516 | free_extent_buffer(tmp); |
| 1500 | return -EAGAIN; | 1517 | } |
| 1518 | return ret; | ||
| 1501 | } | 1519 | } |
| 1502 | 1520 | ||
| 1503 | /* | 1521 | /* |
| @@ -1696,6 +1714,9 @@ cow_done: | |||
| 1696 | if (ret == -EAGAIN) | 1714 | if (ret == -EAGAIN) |
| 1697 | goto again; | 1715 | goto again; |
| 1698 | 1716 | ||
| 1717 | if (ret == -EIO) | ||
| 1718 | goto done; | ||
| 1719 | |||
| 1699 | if (!p->skip_locking) { | 1720 | if (!p->skip_locking) { |
| 1700 | int lret; | 1721 | int lret; |
| 1701 | 1722 | ||
| @@ -1738,6 +1759,8 @@ done: | |||
| 1738 | */ | 1759 | */ |
| 1739 | if (!p->leave_spinning) | 1760 | if (!p->leave_spinning) |
| 1740 | btrfs_set_path_blocking(p); | 1761 | btrfs_set_path_blocking(p); |
| 1762 | if (ret < 0) | ||
| 1763 | btrfs_release_path(root, p); | ||
| 1741 | return ret; | 1764 | return ret; |
| 1742 | } | 1765 | } |
| 1743 | 1766 | ||
| @@ -4212,6 +4235,11 @@ again: | |||
| 4212 | if (ret == -EAGAIN) | 4235 | if (ret == -EAGAIN) |
| 4213 | goto again; | 4236 | goto again; |
| 4214 | 4237 | ||
| 4238 | if (ret < 0) { | ||
| 4239 | btrfs_release_path(root, path); | ||
| 4240 | goto done; | ||
| 4241 | } | ||
| 4242 | |||
| 4215 | if (!path->skip_locking) { | 4243 | if (!path->skip_locking) { |
| 4216 | ret = btrfs_try_spin_lock(next); | 4244 | ret = btrfs_try_spin_lock(next); |
| 4217 | if (!ret) { | 4245 | if (!ret) { |
| @@ -4246,6 +4274,11 @@ again: | |||
| 4246 | if (ret == -EAGAIN) | 4274 | if (ret == -EAGAIN) |
| 4247 | goto again; | 4275 | goto again; |
| 4248 | 4276 | ||
| 4277 | if (ret < 0) { | ||
| 4278 | btrfs_release_path(root, path); | ||
| 4279 | goto done; | ||
| 4280 | } | ||
| 4281 | |||
| 4249 | if (!path->skip_locking) { | 4282 | if (!path->skip_locking) { |
| 4250 | btrfs_assert_tree_locked(path->nodes[level]); | 4283 | btrfs_assert_tree_locked(path->nodes[level]); |
| 4251 | ret = btrfs_try_spin_lock(next); | 4284 | ret = btrfs_try_spin_lock(next); |
