diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-03-19 12:13:25 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-03-21 19:24:31 -0400 |
commit | 835d974fabfa9bff4d173ad03c054ac2f673263f (patch) | |
tree | 7dae22a2ff112055682e79528227814ed7023171 /fs | |
parent | d763448286377b8a0e3f179372e9e292bef3c337 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 35 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 13 |
2 files changed, 42 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 350b9b18140c..a8ff25aedca1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root, | |||
257 | cache->bytes_super += stripe_len; | 257 | cache->bytes_super += stripe_len; |
258 | ret = add_excluded_extent(root, cache->key.objectid, | 258 | ret = add_excluded_extent(root, cache->key.objectid, |
259 | stripe_len); | 259 | stripe_len); |
260 | BUG_ON(ret); /* -ENOMEM */ | 260 | if (ret) |
261 | return ret; | ||
261 | } | 262 | } |
262 | 263 | ||
263 | for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { | 264 | for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { |
@@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root, | |||
265 | ret = btrfs_rmap_block(&root->fs_info->mapping_tree, | 266 | ret = btrfs_rmap_block(&root->fs_info->mapping_tree, |
266 | cache->key.objectid, bytenr, | 267 | cache->key.objectid, bytenr, |
267 | 0, &logical, &nr, &stripe_len); | 268 | 0, &logical, &nr, &stripe_len); |
268 | BUG_ON(ret); /* -ENOMEM */ | 269 | if (ret) |
270 | return ret; | ||
269 | 271 | ||
270 | while (nr--) { | 272 | while (nr--) { |
271 | cache->bytes_super += stripe_len; | 273 | cache->bytes_super += stripe_len; |
272 | ret = add_excluded_extent(root, logical[nr], | 274 | ret = add_excluded_extent(root, logical[nr], |
273 | stripe_len); | 275 | stripe_len); |
274 | BUG_ON(ret); /* -ENOMEM */ | 276 | if (ret) { |
277 | kfree(logical); | ||
278 | return ret; | ||
279 | } | ||
275 | } | 280 | } |
276 | 281 | ||
277 | kfree(logical); | 282 | kfree(logical); |
@@ -7964,7 +7969,17 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
7964 | * info has super bytes accounted for, otherwise we'll think | 7969 | * info has super bytes accounted for, otherwise we'll think |
7965 | * we have more space than we actually do. | 7970 | * we have more space than we actually do. |
7966 | */ | 7971 | */ |
7967 | exclude_super_stripes(root, cache); | 7972 | ret = exclude_super_stripes(root, cache); |
7973 | if (ret) { | ||
7974 | /* | ||
7975 | * We may have excluded something, so call this just in | ||
7976 | * case. | ||
7977 | */ | ||
7978 | free_excluded_extents(root, cache); | ||
7979 | kfree(cache->free_space_ctl); | ||
7980 | kfree(cache); | ||
7981 | goto error; | ||
7982 | } | ||
7968 | 7983 | ||
7969 | /* | 7984 | /* |
7970 | * check for two cases, either we are full, and therefore | 7985 | * check for two cases, either we are full, and therefore |
@@ -8106,7 +8121,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
8106 | 8121 | ||
8107 | cache->last_byte_to_unpin = (u64)-1; | 8122 | cache->last_byte_to_unpin = (u64)-1; |
8108 | cache->cached = BTRFS_CACHE_FINISHED; | 8123 | cache->cached = BTRFS_CACHE_FINISHED; |
8109 | exclude_super_stripes(root, cache); | 8124 | ret = exclude_super_stripes(root, cache); |
8125 | if (ret) { | ||
8126 | /* | ||
8127 | * We may have excluded something, so call this just in | ||
8128 | * case. | ||
8129 | */ | ||
8130 | free_excluded_extents(root, cache); | ||
8131 | kfree(cache->free_space_ctl); | ||
8132 | kfree(cache); | ||
8133 | return ret; | ||
8134 | } | ||
8110 | 8135 | ||
8111 | add_new_free_space(cache, root->fs_info, chunk_offset, | 8136 | add_new_free_space(cache, root->fs_info, chunk_offset, |
8112 | chunk_offset + size); | 8137 | chunk_offset + size); |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5989a92236f7..2854c824ab64 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, | |||
4935 | em = lookup_extent_mapping(em_tree, chunk_start, 1); | 4935 | em = lookup_extent_mapping(em_tree, chunk_start, 1); |
4936 | read_unlock(&em_tree->lock); | 4936 | read_unlock(&em_tree->lock); |
4937 | 4937 | ||
4938 | BUG_ON(!em || em->start != chunk_start); | 4938 | if (!em) { |
4939 | printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n", | ||
4940 | chunk_start); | ||
4941 | return -EIO; | ||
4942 | } | ||
4943 | |||
4944 | if (em->start != chunk_start) { | ||
4945 | printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n", | ||
4946 | em->start, chunk_start); | ||
4947 | free_extent_map(em); | ||
4948 | return -EIO; | ||
4949 | } | ||
4939 | map = (struct map_lookup *)em->bdev; | 4950 | map = (struct map_lookup *)em->bdev; |
4940 | 4951 | ||
4941 | length = em->len; | 4952 | length = em->len; |