Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 57 additions & 13 deletions check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4227,6 +4227,7 @@ static void print_data_backref_error(struct extent_record *rec,
static void print_tree_backref_error(struct extent_record *rec, struct tree_backref *tback)
{
struct extent_backref *back = &tback->node;
u64 root = back->full_backref ? tback->parent : tback->root;

/*
* For tree blocks, we only handle two cases here:
Expand All @@ -4237,20 +4238,28 @@ static void print_tree_backref_error(struct extent_record *rec, struct tree_back
* The refs count check is done by the global backref check at
* all_backpointers_checked().
*/
if (!back->found_extent_tree) {
fprintf(stderr,
if (root == BTRFS_REMAP_TREE_OBJECTID) {
if (back->found_extent_tree) {
fprintf(stderr,
"tree extent[%llu, %llu] %s %llu has unexpected backref item in extent tree\n",
rec->start, rec->max_size,
(back->full_backref ? "parent" : "root"), root);
return;
}
} else {
if (!back->found_extent_tree) {
fprintf(stderr,
"tree extent[%llu, %llu] %s %llu has no backref item in extent tree\n",
rec->start, rec->max_size,
(back->full_backref ? "parent" : "root"),
(back->full_backref ? tback->parent : tback->root));
return;
rec->start, rec->max_size,
(back->full_backref ? "parent" : "root"), root);
return;
}
}
if (!back->found_ref) {
fprintf(stderr,
"tree extent[%llu, %llu] %s %llu has no tree block found\n",
rec->start, rec->max_size,
(back->full_backref ? "parent" : "root"),
(back->full_backref ? tback->parent : tback->root));
(back->full_backref ? "parent" : "root"), root);
return;
}
}
Expand All @@ -4273,7 +4282,19 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)

rbtree_postorder_for_each_entry_safe(back, tmp,
&rec->backref_tree, node) {
if (!back->found_extent_tree) {
bool remap_tree = false;

if (!back->is_data) {
struct tree_backref *tback = to_tree_backref(back);
u64 root = back->full_backref ? tback->parent : tback->root;

if (root == BTRFS_REMAP_TREE_OBJECTID)
remap_tree = true;
}

/* The remap tree doesn't have backrefs. */
if ((!remap_tree && !back->found_extent_tree) ||
(remap_tree && back->found_extent_tree)) {
err = 1;
if (!print_errs)
goto out;
Expand Down Expand Up @@ -4869,7 +4890,8 @@ static void check_extent_type(struct extent_record *rec)

/* metadata extent, check the obvious case first */
if (!(bg_cache->flags & (BTRFS_BLOCK_GROUP_SYSTEM |
BTRFS_BLOCK_GROUP_METADATA))) {
BTRFS_BLOCK_GROUP_METADATA |
BTRFS_BLOCK_GROUP_METADATA_REMAP))) {
rec->wrong_chunk_type = 1;
return;
}
Expand All @@ -4893,6 +4915,8 @@ static void check_extent_type(struct extent_record *rec)

if (tback->root == BTRFS_CHUNK_TREE_OBJECTID)
bg_type = BTRFS_BLOCK_GROUP_SYSTEM;
else if (tback->root == BTRFS_REMAP_TREE_OBJECTID)
bg_type = BTRFS_BLOCK_GROUP_METADATA_REMAP;
else
bg_type = BTRFS_BLOCK_GROUP_METADATA;
if (!(bg_cache->flags & bg_type))
Expand Down Expand Up @@ -4933,6 +4957,7 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache,
rec->parent_generation = tmpl->parent_generation;
rec->generation = tmpl->generation;
rec->level = tmpl->level;
rec->remap_tree = tmpl->remap_tree;
INIT_LIST_HEAD(&rec->backrefs);
INIT_LIST_HEAD(&rec->dups);
INIT_LIST_HEAD(&rec->list);
Expand Down Expand Up @@ -6763,10 +6788,16 @@ static int run_next_block(struct btrfs_root *root,
tmpl.refs = 1;
tmpl.metadata = 1;
tmpl.max_size = size;
tmpl.remap_tree = ri->objectid == BTRFS_REMAP_TREE_OBJECTID ? 1 : 0;
ret = add_extent_rec(extent_cache, &tmpl);
if (ret < 0)
goto out;

if (tmpl.remap_tree) {
update_block_group_used(block_group_cache, ptr,
size);
}

ret = add_tree_backref(extent_cache, ptr, parent,
owner, 1);
if (ret < 0) {
Expand Down Expand Up @@ -6799,6 +6830,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
struct cache_tree *pending,
struct cache_tree *seen,
struct cache_tree *nodes,
struct block_group_tree *block_group_cache,
u64 objectid)
{
struct extent_record tmpl;
Expand All @@ -6816,8 +6848,12 @@ static int add_root_to_pending(struct extent_buffer *buf,
tmpl.refs = 1;
tmpl.metadata = 1;
tmpl.max_size = buf->len;
tmpl.remap_tree = objectid == BTRFS_REMAP_TREE_OBJECTID ? 1 : 0;
add_extent_rec(extent_cache, &tmpl);

if (tmpl.remap_tree)
update_block_group_used(block_group_cache, buf->start, buf->len);

if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
ret = add_tree_backref(extent_cache, buf->start, buf->start,
Expand Down Expand Up @@ -8358,14 +8394,21 @@ static int check_extent_refs(struct btrfs_root *root,
}
}

if (rec->metadata && rec->level != rec->info_level) {
if (rec->metadata && !rec->remap_tree &&
rec->level != rec->info_level) {
fprintf(stderr,
"metadata level mismatch on [%llu, %llu]\n",
rec->start, rec->nr);
cur_err = 1;
}

if (rec->refs != rec->extent_item_refs) {
if (rec->remap_tree && rec->extent_item_refs != 0) {
fprintf(stderr, "ref mismatch on [%llu %llu] ",
rec->start, rec->nr);
fprintf(stderr, "extent item %llu, expected 0\n",
rec->extent_item_refs);
cur_err = 1;
} else if (!rec->remap_tree && rec->refs != rec->extent_item_refs) {
fprintf(stderr, "ref mismatch on [%llu %llu] ",
rec->start, rec->nr);
fprintf(stderr, "extent item %llu, found %llu\n",
Expand Down Expand Up @@ -8904,7 +8947,8 @@ static int deal_root_from_list(struct list_head *list,
break;
}
ret = add_root_to_pending(buf, extent_cache, pending,
seen, nodes, rec->objectid);
seen, nodes, block_group_cache,
rec->objectid);
if (ret < 0)
break;
/*
Expand Down
1 change: 1 addition & 0 deletions check/mode-original.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ struct extent_record {
unsigned int bad_full_backref:1;
unsigned int crossing_stripes:1;
unsigned int wrong_chunk_type:1;
unsigned int remap_tree:1;
};

static inline struct extent_record* to_extent_record(struct list_head *entry)
Expand Down
55 changes: 55 additions & 0 deletions check/repair.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,54 @@ static int populate_used_from_extent_root(struct btrfs_root *root,
return ret;
}

static int walk_remap_tree(struct btrfs_fs_info *fs_info,
struct extent_buffer *node,
struct extent_io_tree *io_tree)
{
u64 bytenr;
struct extent_buffer *eb;
u8 level;
int ret;

level = btrfs_header_level(node);

set_extent_dirty(io_tree, node->start,
node->start + fs_info->nodesize - 1,
GFP_NOFS);

if (level == 0)
return 0;

for (int i = 0; i < btrfs_header_nritems(node); i++) {
bytenr = btrfs_node_blockptr(node, i);

if (level == 1) {
set_extent_dirty(io_tree, bytenr,
bytenr + fs_info->nodesize - 1,
GFP_NOFS);
continue;
}

struct btrfs_tree_parent_check check = {
.level = btrfs_header_level(node) - 1,
};

eb = read_tree_block(fs_info, bytenr, &check);

if (IS_ERR(eb))
return PTR_ERR(eb);

ret = walk_remap_tree(fs_info, eb, io_tree);

free_extent_buffer(eb);

if (ret)
return ret;
}

return 0;
}

int btrfs_mark_used_blocks(struct btrfs_fs_info *fs_info,
struct extent_io_tree *tree)
{
Expand All @@ -296,6 +344,13 @@ int btrfs_mark_used_blocks(struct btrfs_fs_info *fs_info,
break;
}

if (fs_info->remap_root->node) {
ret = walk_remap_tree(fs_info, fs_info->remap_root->node,
tree);
if (ret)
return ret;
}

return ret;
}

Expand Down
Loading