@@ -166,7 +166,7 @@ static int corrupt_keys_in_block(struct btrfs_fs_info *fs_info, u64 bytenr)
{
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, bytenr, 0);
+ eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb))
return -EIO;;
@@ -296,7 +296,9 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
struct extent_buffer *next;
next = read_tree_block(fs_info, btrfs_node_blockptr(eb, i),
- btrfs_node_ptr_generation(eb, i));
+ btrfs_header_owner(eb),
+ btrfs_node_ptr_generation(eb, i),
+ btrfs_header_level(eb) - 1, NULL);
if (!extent_buffer_uptodate(next))
continue;
btrfs_corrupt_extent_tree(trans, root, next);
@@ -860,7 +862,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
return -EINVAL;
}
- eb = read_tree_block(fs_info, block, 0);
+ eb = read_tree_block(fs_info, block, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb)) {
error("couldn't read in tree block %s", field);
return -EINVAL;
@@ -199,7 +199,7 @@ int btrfs_find_root_search(struct btrfs_fs_info *fs_info,
for (offset = chunk_offset;
offset < chunk_offset + chunk_size;
offset += nodesize) {
- eb = read_tree_block(fs_info, offset, 0);
+ eb = read_tree_block(fs_info, offset, 0, 0, 0, NULL);
if (!eb || IS_ERR(eb))
continue;
ret = add_eb_to_result(eb, result, nodesize, filter,
@@ -1898,7 +1898,9 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
free_extent_buffer(next);
reada_walk_down(root, cur, path->slots[*level]);
- next = read_tree_block(gfs_info, bytenr, ptr_gen);
+ next = read_tree_block(gfs_info, bytenr,
+ btrfs_header_owner(cur), ptr_gen,
+ *level - 1, NULL);
if (!extent_buffer_uptodate(next)) {
struct btrfs_key node_key;
@@ -6269,7 +6271,7 @@ static int run_next_block(struct btrfs_root *root,
}
/* fixme, get the real parent transid */
- buf = read_tree_block(gfs_info, bytenr, gen);
+ buf = read_tree_block(gfs_info, bytenr, 0, gen, 0, NULL);
if (!extent_buffer_uptodate(buf)) {
record_bad_block_io(extent_cache, bytenr, size);
goto out;
@@ -8615,7 +8617,8 @@ static int deal_root_from_list(struct list_head *list,
rec = list_entry(list->next,
struct root_item_record, list);
last = 0;
- buf = read_tree_block(gfs_info, rec->bytenr, 0);
+ buf = read_tree_block(gfs_info, rec->bytenr, rec->objectid, 0,
+ rec->level, NULL);
if (!extent_buffer_uptodate(buf)) {
free_extent_buffer(buf);
ret = -EIO;
@@ -132,7 +132,7 @@ static int check_prealloc_shared_data_ref(u64 parent, u64 disk_bytenr)
int i;
int ret = 0;
- eb = read_tree_block(gfs_info, parent, 0);
+ eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb)) {
ret = -EIO;
goto out;
@@ -1127,7 +1127,7 @@ int get_extent_item_generation(u64 bytenr, u64 *gen_ret)
BTRFS_EXTENT_FLAG_TREE_BLOCK) {
struct extent_buffer *eb;
- eb = read_tree_block(gfs_info, bytenr, 0);
+ eb = read_tree_block(gfs_info, bytenr, 0, 0, 0, NULL);
if (extent_buffer_uptodate(eb)) {
*gen_ret = btrfs_header_generation(eb);
ret = 0;
@@ -3748,7 +3748,7 @@ static int query_tree_block_level(u64 bytenr)
btrfs_release_path(&path);
/* Get level from tree block as an alternative source */
- eb = read_tree_block(gfs_info, bytenr, transid);
+ eb = read_tree_block(gfs_info, bytenr, 0, transid, 0, NULL);
if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb);
return -EIO;
@@ -3800,7 +3800,7 @@ static int check_tree_block_backref(u64 root_id, u64 bytenr, int level)
}
/* Read out the tree block to get item/node key */
- eb = read_tree_block(gfs_info, bytenr, 0);
+ eb = read_tree_block(gfs_info, bytenr, root_id, 0, 0, NULL);
if (!extent_buffer_uptodate(eb)) {
err |= REFERENCER_MISSING;
free_extent_buffer(eb);
@@ -3899,7 +3899,7 @@ static int check_shared_block_backref(u64 parent, u64 bytenr, int level)
int found_parent = 0;
int i;
- eb = read_tree_block(gfs_info, parent, 0);
+ eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb))
goto out;
@@ -4072,7 +4072,7 @@ static int check_shared_data_backref(u64 parent, u64 bytenr)
int found_parent = 0;
int i;
- eb = read_tree_block(gfs_info, parent, 0);
+ eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb))
goto out;
@@ -5046,7 +5046,9 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
free_extent_buffer(next);
reada_walk_down(root, cur, path->slots[*level]);
- next = read_tree_block(gfs_info, bytenr, ptr_gen);
+ next = read_tree_block(gfs_info, bytenr,
+ btrfs_header_owner(cur),
+ ptr_gen, *level - 1, NULL);
if (!extent_buffer_uptodate(next)) {
struct btrfs_key node_key;
@@ -720,7 +720,8 @@ static int travel_tree(struct btrfs_fs_info *info, struct btrfs_root *root,
// printf("travel_tree: bytenr: %llu\tnum_bytes: %llu\tref_parent: %llu\n",
// bytenr, num_bytes, ref_parent);
- eb = read_tree_block(info, bytenr, 0);
+ eb = read_tree_block(info, bytenr, btrfs_root_id(root), 0,
+ 0, NULL);
if (!extent_buffer_uptodate(eb))
return -EIO;
@@ -108,7 +108,9 @@ static int traverse_tree_blocks(struct extent_io_tree *tree,
* in, but for now this doesn't actually use the root so
* just pass in extent_root.
*/
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr, key.objectid, 0,
+ btrfs_disk_root_level(eb, ri),
+ NULL);
if (!extent_buffer_uptodate(tmp)) {
fprintf(stderr, "Error reading root block\n");
return -EIO;
@@ -133,7 +135,9 @@ static int traverse_tree_blocks(struct extent_io_tree *tree,
continue;
}
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr,
+ btrfs_header_owner(eb), 0,
+ level - 1, NULL);
if (!extent_buffer_uptodate(tmp)) {
fprintf(stderr, "Error reading tree block\n");
return -EIO;
@@ -58,9 +58,10 @@ static void print_extents(struct extent_buffer *eb)
nr = btrfs_header_nritems(eb);
for (i = 0; i < nr; i++) {
- next = read_tree_block(fs_info,
- btrfs_node_blockptr(eb, i),
- btrfs_node_ptr_generation(eb, i));
+ next = read_tree_block(fs_info, btrfs_node_blockptr(eb, i),
+ btrfs_header_owner(eb),
+ btrfs_node_ptr_generation(eb, i),
+ btrfs_header_level(eb) - 1, NULL);
if (!extent_buffer_uptodate(next))
continue;
if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
@@ -288,7 +289,7 @@ static int dump_print_tree_blocks(struct btrfs_fs_info *fs_info,
goto next;
}
- eb = read_tree_block(fs_info, bytenr, 0);
+ eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(eb)) {
error("failed to read tree block %llu", bytenr);
ret = -EIO;
@@ -625,7 +626,8 @@ again:
offset = btrfs_item_ptr_offset(leaf, slot);
read_extent_buffer(leaf, &ri, offset, sizeof(ri));
- buf = read_tree_block(info, btrfs_root_bytenr(&ri), 0);
+ buf = read_tree_block(info, btrfs_root_bytenr(&ri),
+ key.objectid, 0, 0, NULL);
if (!extent_buffer_uptodate(buf))
goto next;
if (tree_id && found_key.objectid != tree_id) {
@@ -153,7 +153,9 @@ static int walk_nodes(struct btrfs_root *root, struct btrfs_path *path,
path->slots[level] = i;
if ((level - 1) > 0 || find_inline) {
tmp = read_tree_block(root->fs_info, cur_blocknr,
- btrfs_node_ptr_generation(b, i));
+ btrfs_header_owner(b),
+ btrfs_node_ptr_generation(b, i),
+ level - 1, NULL);
if (!extent_buffer_uptodate(tmp)) {
error("failed to read blocknr %llu",
btrfs_node_blockptr(b, i));
@@ -1260,7 +1260,8 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
root_location = btrfs_super_root(fs_info->super_copy);
generation = btrfs_super_generation(fs_info->super_copy);
root->node = read_tree_block(fs_info, root_location,
- generation);
+ btrfs_root_id(root), generation,
+ 0, NULL);
if (!extent_buffer_uptodate(root->node)) {
error("opening tree root failed");
close_ctree(root);
@@ -1527,7 +1528,8 @@ static int cmd_restore(const struct cmd_struct *cmd, int argc, char **argv)
if (fs_location != 0) {
free_extent_buffer(root->node);
- root->node = read_tree_block(root->fs_info, fs_location, 0);
+ root->node = read_tree_block(root->fs_info, fs_location, 0, 0,
+ 0, NULL);
if (!extent_buffer_uptodate(root->node)) {
error("failed to read fs location");
ret = 1;
@@ -707,7 +707,8 @@ static int flush_pending(struct metadump_struct *md, int done)
u64 this_read = min((u64)md->root->fs_info->nodesize,
size);
- eb = read_tree_block(md->root->fs_info, start, 0);
+ eb = read_tree_block(md->root->fs_info, start, 0, 0, 0,
+ NULL);
if (!extent_buffer_uptodate(eb)) {
free(async->buffer);
free(async);
@@ -811,7 +812,7 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
continue;
ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
bytenr = btrfs_disk_root_bytenr(eb, ri);
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(tmp)) {
error("unable to read log root block");
return -EIO;
@@ -822,7 +823,7 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
return ret;
} else {
bytenr = btrfs_node_blockptr(eb, i);
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(tmp)) {
error("unable to read log root block");
return -EIO;
@@ -2697,7 +2698,7 @@ static int iter_tree_blocks(struct btrfs_fs_info *fs_info,
continue;
ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
bytenr = btrfs_disk_root_bytenr(eb, ri);
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(tmp)) {
error("unable to read log root block");
return -EIO;
@@ -2708,7 +2709,7 @@ static int iter_tree_blocks(struct btrfs_fs_info *fs_info,
return ret;
} else {
bytenr = btrfs_node_blockptr(eb, i);
- tmp = read_tree_block(fs_info, bytenr, 0);
+ tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (!extent_buffer_uptodate(tmp)) {
error("unable to read log root block");
return -EIO;
@@ -461,7 +461,8 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
ASSERT(!ref->parent);
ASSERT(!ref->key_for_search.type);
BUG_ON(!ref->wanted_disk_byte);
- eb = read_tree_block(fs_info, ref->wanted_disk_byte, 0);
+ eb = read_tree_block(fs_info, ref->wanted_disk_byte,
+ ref->root_id, 0, ref->level - 1, NULL);
if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb);
return -EIO;
@@ -823,7 +824,8 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
ref->level == 0) {
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, ref->parent, 0);
+ eb = read_tree_block(fs_info, ref->parent, 0,
+ 0, ref->level, NULL);
if (!extent_buffer_uptodate(eb)) {
free_extent_buffer(eb);
ret = -EIO;
@@ -874,7 +874,9 @@ struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
return NULL;
ret = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
- btrfs_node_ptr_generation(parent, slot));
+ btrfs_header_owner(parent),
+ btrfs_node_ptr_generation(parent, slot),
+ level - 1, NULL);
if (!extent_buffer_uptodate(ret))
return ERR_PTR(-EIO);
@@ -337,8 +337,9 @@ int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirr
return 0;
}
-struct extent_buffer* read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 parent_transid)
+struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
+ u64 owner_root, u64 parent_transid,
+ int level, struct btrfs_key *first_key)
{
int ret;
struct extent_buffer *eb;
@@ -510,7 +511,8 @@ static int read_root_node(struct btrfs_fs_info *fs_info,
struct btrfs_root *root, u64 bytenr, u64 gen,
int level)
{
- root->node = read_tree_block(fs_info, bytenr, gen);
+ root->node = read_tree_block(fs_info, bytenr, btrfs_root_id(root),
+ gen, level, NULL);
if (!extent_buffer_uptodate(root->node))
goto err;
if (btrfs_header_level(root->node) != level) {
@@ -138,8 +138,9 @@ static inline u64 btrfs_sb_offset(int mirror)
struct btrfs_device;
int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror);
-struct extent_buffer* read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 parent_transid);
+struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
+ u64 owner_root, u64 parent_transid,
+ int level, struct btrfs_key *first_key);
void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
u64 parent_transid);
@@ -1557,7 +1557,9 @@ static void dfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
for (i = 0; i < nr; i++) {
next = read_tree_block(fs_info, btrfs_node_blockptr(root_eb, i),
- btrfs_node_ptr_generation(root_eb, i));
+ btrfs_header_owner(root_eb),
+ btrfs_node_ptr_generation(root_eb, i),
+ root_eb_level, NULL);
if (!extent_buffer_uptodate(next)) {
fprintf(stderr, "failed to read %llu in tree %llu\n",
btrfs_node_blockptr(root_eb, i),
@@ -111,7 +111,7 @@ static int change_extent_tree_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsi
goto next;
bytenr = key.objectid;
- eb = read_tree_block(fs_info, bytenr, 0);
+ eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
if (IS_ERR(eb)) {
error("failed to read tree block: %llu", bytenr);
ret = PTR_ERR(eb);
The in-kernel version of read_tree_block adds some extra sanity checks to make sure we don't return blocks that don't match what we expect. This includes the owning root, the level, and the expected first key. We don't actually do these checks in btrfs-progs, however kernel code we're going to sync will expect this calling convention, so update it to match the in-kernel code and then update all the callers. Signed-off-by: Josef Bacik <josef@toxicpanda.com> --- btrfs-corrupt-block.c | 8 +++++--- btrfs-find-root.c | 2 +- check/main.c | 9 ++++++--- check/mode-common.c | 4 ++-- check/mode-lowmem.c | 12 +++++++----- check/qgroup-verify.c | 3 ++- check/repair.c | 8 ++++++-- cmds/inspect-dump-tree.c | 12 +++++++----- cmds/inspect-tree-stats.c | 4 +++- cmds/restore.c | 6 ++++-- image/main.c | 11 ++++++----- kernel-shared/backref.c | 6 ++++-- kernel-shared/ctree.c | 4 +++- kernel-shared/disk-io.c | 8 +++++--- kernel-shared/disk-io.h | 5 +++-- kernel-shared/print-tree.c | 4 +++- tune/change-uuid.c | 2 +- 17 files changed, 68 insertions(+), 40 deletions(-)