Btrfs: handle a bogus chunk tree nicely
If you restore a btrfs-image file system and try to mount that file system we'll panic. That's because btrfs-image restores and just makes one big chunk to envelope the whole disk, since they are really only meant to be messed with by our btrfs-progs. So fix up btrfs_rmap_block and the callers of it for mount so that we no longer panic but instead just return an error and fail to mount. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
parent
d763448286
commit
835d974fab
2 changed files with 42 additions and 6 deletions
|
@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
|||
cache->bytes_super += stripe_len;
|
||||
ret = add_excluded_extent(root, cache->key.objectid,
|
||||
stripe_len);
|
||||
BUG_ON(ret); /* -ENOMEM */
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||
|
@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
|||
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
||||
cache->key.objectid, bytenr,
|
||||
0, &logical, &nr, &stripe_len);
|
||||
BUG_ON(ret); /* -ENOMEM */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (nr--) {
|
||||
cache->bytes_super += stripe_len;
|
||||
ret = add_excluded_extent(root, logical[nr],
|
||||
stripe_len);
|
||||
BUG_ON(ret); /* -ENOMEM */
|
||||
if (ret) {
|
||||
kfree(logical);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(logical);
|
||||
|
@ -7964,7 +7969,17 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
|||
* info has super bytes accounted for, otherwise we'll think
|
||||
* we have more space than we actually do.
|
||||
*/
|
||||
exclude_super_stripes(root, cache);
|
||||
ret = exclude_super_stripes(root, cache);
|
||||
if (ret) {
|
||||
/*
|
||||
* We may have excluded something, so call this just in
|
||||
* case.
|
||||
*/
|
||||
free_excluded_extents(root, cache);
|
||||
kfree(cache->free_space_ctl);
|
||||
kfree(cache);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for two cases, either we are full, and therefore
|
||||
|
@ -8106,7 +8121,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
|||
|
||||
cache->last_byte_to_unpin = (u64)-1;
|
||||
cache->cached = BTRFS_CACHE_FINISHED;
|
||||
exclude_super_stripes(root, cache);
|
||||
ret = exclude_super_stripes(root, cache);
|
||||
if (ret) {
|
||||
/*
|
||||
* We may have excluded something, so call this just in
|
||||
* case.
|
||||
*/
|
||||
free_excluded_extents(root, cache);
|
||||
kfree(cache->free_space_ctl);
|
||||
kfree(cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
add_new_free_space(cache, root->fs_info, chunk_offset,
|
||||
chunk_offset + size);
|
||||
|
|
|
@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
|
|||
em = lookup_extent_mapping(em_tree, chunk_start, 1);
|
||||
read_unlock(&em_tree->lock);
|
||||
|
||||
BUG_ON(!em || em->start != chunk_start);
|
||||
if (!em) {
|
||||
printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n",
|
||||
chunk_start);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (em->start != chunk_start) {
|
||||
printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n",
|
||||
em->start, chunk_start);
|
||||
free_extent_map(em);
|
||||
return -EIO;
|
||||
}
|
||||
map = (struct map_lookup *)em->bdev;
|
||||
|
||||
length = em->len;
|
||||
|
|
Loading…
Reference in a new issue