|
@@ -1469,6 +1469,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
u32 blocksize;
|
|
|
struct extent_buffer *b = *eb_ret;
|
|
|
struct extent_buffer *tmp;
|
|
|
+ int ret;
|
|
|
|
|
|
blocknr = btrfs_node_blockptr(b, slot);
|
|
|
gen = btrfs_node_ptr_generation(b, slot);
|
|
@@ -1476,6 +1477,10 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
tmp = btrfs_find_tree_block(root, blocknr, blocksize);
|
|
|
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
|
|
|
+ /*
|
|
|
+ * we found an up to date block without sleeping, return
|
|
|
+ * right away
|
|
|
+ */
|
|
|
*eb_ret = tmp;
|
|
|
return 0;
|
|
|
}
|
|
@@ -1483,7 +1488,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
/*
|
|
|
* reduce lock contention at high levels
|
|
|
* of the btree by dropping locks before
|
|
|
- * we read.
|
|
|
+ * we read. Don't release the lock on the current
|
|
|
+ * level because we need to walk this node to figure
|
|
|
+ * out which blocks to read.
|
|
|
*/
|
|
|
btrfs_unlock_up_safe(p, level + 1);
|
|
|
btrfs_set_path_blocking(p);
|
|
@@ -1494,10 +1501,21 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
reada_for_search(root, p, level, slot, key->objectid);
|
|
|
|
|
|
btrfs_release_path(NULL, p);
|
|
|
+
|
|
|
+ ret = -EAGAIN;
|
|
|
tmp = read_tree_block(root, blocknr, blocksize, gen);
|
|
|
- if (tmp)
|
|
|
+ if (tmp) {
|
|
|
+ /*
|
|
|
+ * If the read above didn't mark this buffer up to date,
|
|
|
+ * it will never end up being up to date. Set ret to EIO now
|
|
|
+ * and give up so that our caller doesn't loop forever
|
|
|
+ * on our EAGAINs.
|
|
|
+ */
|
|
|
+ if (!btrfs_buffer_uptodate(tmp, 0))
|
|
|
+ ret = -EIO;
|
|
|
free_extent_buffer(tmp);
|
|
|
- return -EAGAIN;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1696,6 +1714,9 @@ cow_done:
|
|
|
if (ret == -EAGAIN)
|
|
|
goto again;
|
|
|
|
|
|
+ if (ret == -EIO)
|
|
|
+ goto done;
|
|
|
+
|
|
|
if (!p->skip_locking) {
|
|
|
int lret;
|
|
|
|
|
@@ -1738,6 +1759,8 @@ done:
|
|
|
*/
|
|
|
if (!p->leave_spinning)
|
|
|
btrfs_set_path_blocking(p);
|
|
|
+ if (ret < 0)
|
|
|
+ btrfs_release_path(root, p);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -4212,6 +4235,11 @@ again:
|
|
|
if (ret == -EAGAIN)
|
|
|
goto again;
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_release_path(root, path);
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
if (!path->skip_locking) {
|
|
|
ret = btrfs_try_spin_lock(next);
|
|
|
if (!ret) {
|
|
@@ -4246,6 +4274,11 @@ again:
|
|
|
if (ret == -EAGAIN)
|
|
|
goto again;
|
|
|
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_release_path(root, path);
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
if (!path->skip_locking) {
|
|
|
btrfs_assert_tree_locked(path->nodes[level]);
|
|
|
ret = btrfs_try_spin_lock(next);
|