mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-01 22:48:06 +00:00
btrfs-progs: fsck: Avoid abort and BUG_ON in add_tree_backref
Add_tree_backref() can cause BUG_ON() and abort() in quite a lot of cases, from the ENOMEM to existing tree backref records. Change all these BUG_ON() and abort() to return proper values. And modify all callers to handle such problems. Reported-by: Lukas Lueg <lukas.lueg@gmail.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
77deae9cb7
commit
9a0f2f1e53
75
cmds-check.c
75
cmds-check.c
@ -4864,20 +4864,25 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||||||
|
|
||||||
add_extent_rec_nolookup(extent_cache, &tmpl);
|
add_extent_rec_nolookup(extent_cache, &tmpl);
|
||||||
|
|
||||||
|
/* really a bug in cache_extent implement now */
|
||||||
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
abort();
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = container_of(cache, struct extent_record, cache);
|
rec = container_of(cache, struct extent_record, cache);
|
||||||
if (rec->start != bytenr) {
|
if (rec->start != bytenr) {
|
||||||
abort();
|
/*
|
||||||
|
* Several cause, from unaligned bytenr to over lapping extents
|
||||||
|
*/
|
||||||
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
back = find_tree_backref(rec, parent, root);
|
back = find_tree_backref(rec, parent, root);
|
||||||
if (!back) {
|
if (!back) {
|
||||||
back = alloc_tree_backref(rec, parent, root);
|
back = alloc_tree_backref(rec, parent, root);
|
||||||
BUG_ON(!back);
|
if (!back)
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_ref) {
|
if (found_ref) {
|
||||||
@ -5154,16 +5159,18 @@ static int process_extent_ref_v0(struct cache_tree *extent_cache,
|
|||||||
{
|
{
|
||||||
struct btrfs_extent_ref_v0 *ref0;
|
struct btrfs_extent_ref_v0 *ref0;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
|
int ret;
|
||||||
|
|
||||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||||
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
|
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
|
||||||
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
|
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
|
||||||
add_tree_backref(extent_cache, key.objectid, key.offset, 0, 0);
|
ret = add_tree_backref(extent_cache, key.objectid, key.offset,
|
||||||
|
0, 0);
|
||||||
} else {
|
} else {
|
||||||
add_data_backref(extent_cache, key.objectid, key.offset, 0,
|
ret = add_data_backref(extent_cache, key.objectid, key.offset,
|
||||||
0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
|
0, 0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -5406,6 +5413,7 @@ static int process_extent_item(struct btrfs_root *root,
|
|||||||
struct extent_record tmpl;
|
struct extent_record tmpl;
|
||||||
unsigned long end;
|
unsigned long end;
|
||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
|
int ret;
|
||||||
int type;
|
int type;
|
||||||
u32 item_size = btrfs_item_size_nr(eb, slot);
|
u32 item_size = btrfs_item_size_nr(eb, slot);
|
||||||
u64 refs = 0;
|
u64 refs = 0;
|
||||||
@ -5485,12 +5493,18 @@ static int process_extent_item(struct btrfs_root *root,
|
|||||||
offset = btrfs_extent_inline_ref_offset(eb, iref);
|
offset = btrfs_extent_inline_ref_offset(eb, iref);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BTRFS_TREE_BLOCK_REF_KEY:
|
case BTRFS_TREE_BLOCK_REF_KEY:
|
||||||
add_tree_backref(extent_cache, key.objectid,
|
ret = add_tree_backref(extent_cache, key.objectid,
|
||||||
0, offset, 0);
|
0, offset, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
error("add_tree_backref failed: %s",
|
||||||
|
strerror(-ret));
|
||||||
break;
|
break;
|
||||||
case BTRFS_SHARED_BLOCK_REF_KEY:
|
case BTRFS_SHARED_BLOCK_REF_KEY:
|
||||||
add_tree_backref(extent_cache, key.objectid,
|
ret = add_tree_backref(extent_cache, key.objectid,
|
||||||
offset, 0, 0);
|
offset, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
error("add_tree_backref failed: %s",
|
||||||
|
strerror(-ret));
|
||||||
break;
|
break;
|
||||||
case BTRFS_EXTENT_DATA_REF_KEY:
|
case BTRFS_EXTENT_DATA_REF_KEY:
|
||||||
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
|
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
|
||||||
@ -6413,13 +6427,19 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key.type == BTRFS_TREE_BLOCK_REF_KEY) {
|
if (key.type == BTRFS_TREE_BLOCK_REF_KEY) {
|
||||||
add_tree_backref(extent_cache, key.objectid, 0,
|
ret = add_tree_backref(extent_cache,
|
||||||
key.offset, 0);
|
key.objectid, 0, key.offset, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
error("add_tree_backref failed: %s",
|
||||||
|
strerror(-ret));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) {
|
if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) {
|
||||||
add_tree_backref(extent_cache, key.objectid,
|
ret = add_tree_backref(extent_cache,
|
||||||
key.offset, 0, 0);
|
key.objectid, key.offset, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
error("add_tree_backref failed: %s",
|
||||||
|
strerror(-ret));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
|
if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
|
||||||
@ -6517,9 +6537,16 @@ static int run_next_block(struct btrfs_root *root,
|
|||||||
tmpl.metadata = 1;
|
tmpl.metadata = 1;
|
||||||
tmpl.max_size = size;
|
tmpl.max_size = size;
|
||||||
ret = add_extent_rec(extent_cache, &tmpl);
|
ret = add_extent_rec(extent_cache, &tmpl);
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
add_tree_backref(extent_cache, ptr, parent, owner, 1);
|
ret = add_tree_backref(extent_cache, ptr, parent,
|
||||||
|
owner, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
error("add_tree_backref failed: %s",
|
||||||
|
strerror(-ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (level > 1) {
|
if (level > 1) {
|
||||||
add_pending(nodes, seen, ptr, size);
|
add_pending(nodes, seen, ptr, size);
|
||||||
@ -6553,6 +6580,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
|
|||||||
u64 objectid)
|
u64 objectid)
|
||||||
{
|
{
|
||||||
struct extent_record tmpl;
|
struct extent_record tmpl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (btrfs_header_level(buf) > 0)
|
if (btrfs_header_level(buf) > 0)
|
||||||
add_pending(nodes, seen, buf->start, buf->len);
|
add_pending(nodes, seen, buf->start, buf->len);
|
||||||
@ -6570,11 +6598,12 @@ static int add_root_to_pending(struct extent_buffer *buf,
|
|||||||
|
|
||||||
if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
||||||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
|
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
|
||||||
add_tree_backref(extent_cache, buf->start, buf->start,
|
ret = add_tree_backref(extent_cache, buf->start, buf->start,
|
||||||
0, 1);
|
0, 1);
|
||||||
else
|
else
|
||||||
add_tree_backref(extent_cache, buf->start, 0, objectid, 1);
|
ret = add_tree_backref(extent_cache, buf->start, 0, objectid,
|
||||||
return 0;
|
1);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* as we fix the tree, we might be deleting blocks that
|
/* as we fix the tree, we might be deleting blocks that
|
||||||
@ -8425,8 +8454,10 @@ static int deal_root_from_list(struct list_head *list,
|
|||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
add_root_to_pending(buf, extent_cache, pending,
|
ret = add_root_to_pending(buf, extent_cache, pending,
|
||||||
seen, nodes, rec->objectid);
|
seen, nodes, rec->objectid);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
/*
|
/*
|
||||||
* To rebuild extent tree, we need deal with snapshot
|
* To rebuild extent tree, we need deal with snapshot
|
||||||
* one by one, otherwise we deal with node firstly which
|
* one by one, otherwise we deal with node firstly which
|
||||||
|
Loading…
Reference in New Issue
Block a user