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);
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;
}
/*
* 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);
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;
}
/*
if (ret == -EAGAIN)
goto again;
+ if (ret == -EIO)
+ goto done;
+
if (!p->skip_locking) {
int lret;
*/
if (!p->leave_spinning)
btrfs_set_path_blocking(p);
+ if (ret < 0)
+ btrfs_release_path(root, p);
return ret;
}
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) {
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);