diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index e5b2533b691a..fedf8b9f03a2 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1325,12 +1325,12 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1325 | int ret = 0; | 1325 | int ret = 0; |
1326 | int blocksize; | 1326 | int blocksize; |
1327 | 1327 | ||
1328 | parent = path->nodes[level - 1]; | 1328 | parent = path->nodes[level + 1]; |
1329 | if (!parent) | 1329 | if (!parent) |
1330 | return 0; | 1330 | return 0; |
1331 | 1331 | ||
1332 | nritems = btrfs_header_nritems(parent); | 1332 | nritems = btrfs_header_nritems(parent); |
1333 | slot = path->slots[level]; | 1333 | slot = path->slots[level + 1]; |
1334 | blocksize = btrfs_level_size(root, level); | 1334 | blocksize = btrfs_level_size(root, level); |
1335 | 1335 | ||
1336 | if (slot > 0) { | 1336 | if (slot > 0) { |
@@ -1341,7 +1341,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1341 | block1 = 0; | 1341 | block1 = 0; |
1342 | free_extent_buffer(eb); | 1342 | free_extent_buffer(eb); |
1343 | } | 1343 | } |
1344 | if (slot < nritems) { | 1344 | if (slot + 1 < nritems) { |
1345 | block2 = btrfs_node_blockptr(parent, slot + 1); | 1345 | block2 = btrfs_node_blockptr(parent, slot + 1); |
1346 | gen = btrfs_node_ptr_generation(parent, slot + 1); | 1346 | gen = btrfs_node_ptr_generation(parent, slot + 1); |
1347 | eb = btrfs_find_tree_block(root, block2, blocksize); | 1347 | eb = btrfs_find_tree_block(root, block2, blocksize); |
@@ -1351,7 +1351,11 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1351 | } | 1351 | } |
1352 | if (block1 || block2) { | 1352 | if (block1 || block2) { |
1353 | ret = -EAGAIN; | 1353 | ret = -EAGAIN; |
1354 | |||
1355 | /* release the whole path */ | ||
1354 | btrfs_release_path(root, path); | 1356 | btrfs_release_path(root, path); |
1357 | |||
1358 | /* read the blocks */ | ||
1355 | if (block1) | 1359 | if (block1) |
1356 | readahead_tree_block(root, block1, blocksize, 0); | 1360 | readahead_tree_block(root, block1, blocksize, 0); |
1357 | if (block2) | 1361 | if (block2) |
@@ -1361,7 +1365,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1361 | eb = read_tree_block(root, block1, blocksize, 0); | 1365 | eb = read_tree_block(root, block1, blocksize, 0); |
1362 | free_extent_buffer(eb); | 1366 | free_extent_buffer(eb); |
1363 | } | 1367 | } |
1364 | if (block1) { | 1368 | if (block2) { |
1365 | eb = read_tree_block(root, block2, blocksize, 0); | 1369 | eb = read_tree_block(root, block2, blocksize, 0); |
1366 | free_extent_buffer(eb); | 1370 | free_extent_buffer(eb); |
1367 | } | 1371 | } |
@@ -1465,6 +1469,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1465 | u32 blocksize; | 1469 | u32 blocksize; |
1466 | struct extent_buffer *b = *eb_ret; | 1470 | struct extent_buffer *b = *eb_ret; |
1467 | struct extent_buffer *tmp; | 1471 | struct extent_buffer *tmp; |
1472 | int ret; | ||
1468 | 1473 | ||
1469 | blocknr = btrfs_node_blockptr(b, slot); | 1474 | blocknr = btrfs_node_blockptr(b, slot); |
1470 | gen = btrfs_node_ptr_generation(b, slot); | 1475 | gen = btrfs_node_ptr_generation(b, slot); |
@@ -1472,6 +1477,10 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1472 | 1477 | ||
1473 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1478 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
1474 | 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 | */ | ||
1475 | *eb_ret = tmp; | 1484 | *eb_ret = tmp; |
1476 | return 0; | 1485 | return 0; |
1477 | } | 1486 | } |
@@ -1479,18 +1488,34 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1479 | /* | 1488 | /* |
1480 | * reduce lock contention at high levels | 1489 | * reduce lock contention at high levels |
1481 | * of the btree by dropping locks before | 1490 | * of the btree by dropping locks before |
1482 | * 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. | ||
1483 | */ | 1494 | */ |
1484 | btrfs_release_path(NULL, p); | 1495 | btrfs_unlock_up_safe(p, level + 1); |
1496 | btrfs_set_path_blocking(p); | ||
1497 | |||
1485 | if (tmp) | 1498 | if (tmp) |
1486 | free_extent_buffer(tmp); | 1499 | free_extent_buffer(tmp); |
1487 | if (p->reada) | 1500 | if (p->reada) |
1488 | reada_for_search(root, p, level, slot, key->objectid); | 1501 | reada_for_search(root, p, level, slot, key->objectid); |
1489 | 1502 | ||
1503 | btrfs_release_path(NULL, p); | ||
1504 | |||
1505 | ret = -EAGAIN; | ||
1490 | tmp = read_tree_block(root, blocknr, blocksize, gen); | 1506 | tmp = read_tree_block(root, blocknr, blocksize, gen); |
1491 | 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; | ||
1492 | free_extent_buffer(tmp); | 1516 | free_extent_buffer(tmp); |
1493 | return -EAGAIN; | 1517 | } |
1518 | return ret; | ||
1494 | } | 1519 | } |
1495 | 1520 | ||
1496 | /* | 1521 | /* |
@@ -1689,6 +1714,9 @@ cow_done: | |||
1689 | if (ret == -EAGAIN) | 1714 | if (ret == -EAGAIN) |
1690 | goto again; | 1715 | goto again; |
1691 | 1716 | ||
1717 | if (ret == -EIO) | ||
1718 | goto done; | ||
1719 | |||
1692 | if (!p->skip_locking) { | 1720 | if (!p->skip_locking) { |
1693 | int lret; | 1721 | int lret; |
1694 | 1722 | ||
@@ -1731,6 +1759,8 @@ done: | |||
1731 | */ | 1759 | */ |
1732 | if (!p->leave_spinning) | 1760 | if (!p->leave_spinning) |
1733 | btrfs_set_path_blocking(p); | 1761 | btrfs_set_path_blocking(p); |
1762 | if (ret < 0) | ||
1763 | btrfs_release_path(root, p); | ||
1734 | return ret; | 1764 | return ret; |
1735 | } | 1765 | } |
1736 | 1766 | ||
@@ -4205,6 +4235,11 @@ again: | |||
4205 | if (ret == -EAGAIN) | 4235 | if (ret == -EAGAIN) |
4206 | goto again; | 4236 | goto again; |
4207 | 4237 | ||
4238 | if (ret < 0) { | ||
4239 | btrfs_release_path(root, path); | ||
4240 | goto done; | ||
4241 | } | ||
4242 | |||
4208 | if (!path->skip_locking) { | 4243 | if (!path->skip_locking) { |
4209 | ret = btrfs_try_spin_lock(next); | 4244 | ret = btrfs_try_spin_lock(next); |
4210 | if (!ret) { | 4245 | if (!ret) { |
@@ -4239,6 +4274,11 @@ again: | |||
4239 | if (ret == -EAGAIN) | 4274 | if (ret == -EAGAIN) |
4240 | goto again; | 4275 | goto again; |
4241 | 4276 | ||
4277 | if (ret < 0) { | ||
4278 | btrfs_release_path(root, path); | ||
4279 | goto done; | ||
4280 | } | ||
4281 | |||
4242 | if (!path->skip_locking) { | 4282 | if (!path->skip_locking) { |
4243 | btrfs_assert_tree_locked(path->nodes[level]); | 4283 | btrfs_assert_tree_locked(path->nodes[level]); |
4244 | ret = btrfs_try_spin_lock(next); | 4284 | ret = btrfs_try_spin_lock(next); |