Commit 64c043de authored by Liu Bo's avatar Liu Bo Committed by Chris Mason

Btrfs: fix up read_tree_block to return proper error

The return value of read_tree_block() can confuse callers as it always
returns NULL for either -ENOMEM or -EIO, so it's likely that callers
parse it to a wrong error, for instance, in btrfs_read_tree_root().

This fixes the above issue.
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.cz>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 8635eda9
...@@ -491,7 +491,9 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info, ...@@ -491,7 +491,9 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
BUG_ON(!ref->wanted_disk_byte); BUG_ON(!ref->wanted_disk_byte);
eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte, eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte,
0); 0);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
return PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
return -EIO; return -EIO;
} }
...@@ -1034,7 +1036,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -1034,7 +1036,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
eb = read_tree_block(fs_info->extent_root, eb = read_tree_block(fs_info->extent_root,
ref->parent, 0); ref->parent, 0);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
goto out;
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
ret = -EIO; ret = -EIO;
goto out; goto out;
......
...@@ -1439,8 +1439,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1439,8 +1439,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
btrfs_tree_read_unlock(eb_root); btrfs_tree_read_unlock(eb_root);
free_extent_buffer(eb_root); free_extent_buffer(eb_root);
old = read_tree_block(root, logical, 0); old = read_tree_block(root, logical, 0);
if (WARN_ON(!old || !extent_buffer_uptodate(old))) { if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) {
free_extent_buffer(old); if (!IS_ERR(old))
free_extent_buffer(old);
btrfs_warn(root->fs_info, btrfs_warn(root->fs_info,
"failed to read tree block %llu from get_old_root", logical); "failed to read tree block %llu from get_old_root", logical);
} else { } else {
...@@ -1685,7 +1686,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -1685,7 +1686,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
if (!cur || !uptodate) { if (!cur || !uptodate) {
if (!cur) { if (!cur) {
cur = read_tree_block(root, blocknr, gen); cur = read_tree_block(root, blocknr, gen);
if (!cur || !extent_buffer_uptodate(cur)) { if (IS_ERR(cur)) {
return PTR_ERR(cur);
} else if (!extent_buffer_uptodate(cur)) {
free_extent_buffer(cur); free_extent_buffer(cur);
return -EIO; return -EIO;
} }
...@@ -1864,8 +1867,9 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, ...@@ -1864,8 +1867,9 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
eb = read_tree_block(root, btrfs_node_blockptr(parent, slot), eb = read_tree_block(root, btrfs_node_blockptr(parent, slot),
btrfs_node_ptr_generation(parent, slot)); btrfs_node_ptr_generation(parent, slot));
if (eb && !extent_buffer_uptodate(eb)) { if (IS_ERR(eb) || !extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); if (!IS_ERR(eb))
free_extent_buffer(eb);
eb = NULL; eb = NULL;
} }
...@@ -2494,7 +2498,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, ...@@ -2494,7 +2498,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
ret = -EAGAIN; ret = -EAGAIN;
tmp = read_tree_block(root, blocknr, 0); tmp = read_tree_block(root, blocknr, 0);
if (tmp) { if (!IS_ERR(tmp)) {
/* /*
* If the read above didn't mark this buffer up to date, * 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 * it will never end up being up to date. Set ret to EIO now
......
...@@ -1149,12 +1149,12 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, ...@@ -1149,12 +1149,12 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
buf = btrfs_find_create_tree_block(root, bytenr); buf = btrfs_find_create_tree_block(root, bytenr);
if (!buf) if (!buf)
return NULL; return ERR_PTR(-ENOMEM);
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid); ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
if (ret) { if (ret) {
free_extent_buffer(buf); free_extent_buffer(buf);
return NULL; return ERR_PTR(ret);
} }
return buf; return buf;
...@@ -1509,20 +1509,19 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, ...@@ -1509,20 +1509,19 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
generation = btrfs_root_generation(&root->root_item); generation = btrfs_root_generation(&root->root_item);
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
generation); generation);
if (!root->node) { if (IS_ERR(root->node)) {
ret = -ENOMEM; ret = PTR_ERR(root->node);
goto find_fail; goto find_fail;
} else if (!btrfs_buffer_uptodate(root->node, generation, 0)) { } else if (!btrfs_buffer_uptodate(root->node, generation, 0)) {
ret = -EIO; ret = -EIO;
goto read_fail; free_extent_buffer(root->node);
goto find_fail;
} }
root->commit_root = btrfs_root_node(root); root->commit_root = btrfs_root_node(root);
out: out:
btrfs_free_path(path); btrfs_free_path(path);
return root; return root;
read_fail:
free_extent_buffer(root->node);
find_fail: find_fail:
kfree(root); kfree(root);
alloc_fail: alloc_fail:
...@@ -2320,8 +2319,11 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, ...@@ -2320,8 +2319,11 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
log_tree_root->node = read_tree_block(tree_root, bytenr, log_tree_root->node = read_tree_block(tree_root, bytenr,
fs_info->generation + 1); fs_info->generation + 1);
if (!log_tree_root->node || if (IS_ERR(log_tree_root->node)) {
!extent_buffer_uptodate(log_tree_root->node)) { printk(KERN_ERR "BTRFS: failed to read log tree\n");
kfree(log_tree_root);
return PTR_ERR(log_tree_root->node);
} else if (!extent_buffer_uptodate(log_tree_root->node)) {
printk(KERN_ERR "BTRFS: failed to read log tree\n"); printk(KERN_ERR "BTRFS: failed to read log tree\n");
free_extent_buffer(log_tree_root->node); free_extent_buffer(log_tree_root->node);
kfree(log_tree_root); kfree(log_tree_root);
...@@ -2797,8 +2799,8 @@ int open_ctree(struct super_block *sb, ...@@ -2797,8 +2799,8 @@ int open_ctree(struct super_block *sb,
chunk_root->node = read_tree_block(chunk_root, chunk_root->node = read_tree_block(chunk_root,
btrfs_super_chunk_root(disk_super), btrfs_super_chunk_root(disk_super),
generation); generation);
if (!chunk_root->node || if (IS_ERR(chunk_root->node) ||
!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { !extent_buffer_uptodate(chunk_root->node)) {
printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n", printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n",
sb->s_id); sb->s_id);
goto fail_tree_roots; goto fail_tree_roots;
...@@ -2834,8 +2836,8 @@ int open_ctree(struct super_block *sb, ...@@ -2834,8 +2836,8 @@ int open_ctree(struct super_block *sb,
tree_root->node = read_tree_block(tree_root, tree_root->node = read_tree_block(tree_root,
btrfs_super_root(disk_super), btrfs_super_root(disk_super),
generation); generation);
if (!tree_root->node || if (IS_ERR(tree_root->node) ||
!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { !extent_buffer_uptodate(tree_root->node)) {
printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n", printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
sb->s_id); sb->s_id);
......
...@@ -7979,9 +7979,12 @@ static int account_shared_subtree(struct btrfs_trans_handle *trans, ...@@ -7979,9 +7979,12 @@ static int account_shared_subtree(struct btrfs_trans_handle *trans,
child_gen = btrfs_node_ptr_generation(eb, parent_slot); child_gen = btrfs_node_ptr_generation(eb, parent_slot);
eb = read_tree_block(root, child_bytenr, child_gen); eb = read_tree_block(root, child_bytenr, child_gen);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
ret = -EIO; ret = PTR_ERR(eb);
goto out;
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
ret = -EIO;
goto out; goto out;
} }
...@@ -8211,7 +8214,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, ...@@ -8211,7 +8214,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
if (reada && level == 1) if (reada && level == 1)
reada_walk_down(trans, root, wc, path); reada_walk_down(trans, root, wc, path);
next = read_tree_block(root, bytenr, generation); next = read_tree_block(root, bytenr, generation);
if (!next || !extent_buffer_uptodate(next)) { if (IS_ERR(next)) {
return PTR_ERR(next);
} else if (!extent_buffer_uptodate(next)) {
free_extent_buffer(next); free_extent_buffer(next);
return -EIO; return -EIO;
} }
......
...@@ -1847,8 +1847,10 @@ int replace_path(struct btrfs_trans_handle *trans, ...@@ -1847,8 +1847,10 @@ int replace_path(struct btrfs_trans_handle *trans,
} }
eb = read_tree_block(dest, old_bytenr, old_ptr_gen); eb = read_tree_block(dest, old_bytenr, old_ptr_gen);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
ret = (!eb) ? -ENOMEM : -EIO; ret = PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
ret = -EIO;
free_extent_buffer(eb); free_extent_buffer(eb);
break; break;
} }
...@@ -2002,7 +2004,9 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path, ...@@ -2002,7 +2004,9 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
bytenr = btrfs_node_blockptr(eb, path->slots[i]); bytenr = btrfs_node_blockptr(eb, path->slots[i]);
eb = read_tree_block(root, bytenr, ptr_gen); eb = read_tree_block(root, bytenr, ptr_gen);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
return PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
return -EIO; return -EIO;
} }
...@@ -2710,7 +2714,10 @@ static int do_relocation(struct btrfs_trans_handle *trans, ...@@ -2710,7 +2714,10 @@ static int do_relocation(struct btrfs_trans_handle *trans,
blocksize = root->nodesize; blocksize = root->nodesize;
generation = btrfs_node_ptr_generation(upper->eb, slot); generation = btrfs_node_ptr_generation(upper->eb, slot);
eb = read_tree_block(root, bytenr, generation); eb = read_tree_block(root, bytenr, generation);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
err = PTR_ERR(eb);
goto next;
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
err = -EIO; err = -EIO;
goto next; goto next;
...@@ -2873,7 +2880,9 @@ static int get_tree_block_key(struct reloc_control *rc, ...@@ -2873,7 +2880,9 @@ static int get_tree_block_key(struct reloc_control *rc,
BUG_ON(block->key_ready); BUG_ON(block->key_ready);
eb = read_tree_block(rc->extent_root, block->bytenr, eb = read_tree_block(rc->extent_root, block->bytenr,
block->key.offset); block->key.offset);
if (!eb || !extent_buffer_uptodate(eb)) { if (IS_ERR(eb)) {
return PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb); free_extent_buffer(eb);
return -EIO; return -EIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment