Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+7 −2
Original line number Original line Diff line number Diff line
@@ -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,


				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;
+10 −6
Original line number Original line Diff line number Diff line
@@ -1439,7 +1439,8 @@ 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))) {
			if (!IS_ERR(old))
				free_extent_buffer(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);
@@ -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,7 +1867,8 @@ 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)) {
		if (!IS_ERR(eb))
			free_extent_buffer(eb);
			free_extent_buffer(eb);
		eb = NULL;
		eb = NULL;
	}
	}
@@ -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
+15 −13
Original line number Original line Diff line number Diff line
@@ -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,
	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,


	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,
	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,
	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);


+8 −3
Original line number Original line Diff line number Diff line
@@ -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,
		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;
		}
		}
+14 −5
Original line number Original line Diff line number Diff line
@@ -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,


		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,
		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,
	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;
	}
	}