| From 4867268c57ff709a7b6b86ae6f6537d846d1443a Mon Sep 17 00:00:00 2001 |
| From: Josef Bacik <jbacik@fb.com> |
| Date: Fri, 23 Sep 2016 13:23:28 +0200 |
| Subject: Btrfs: don't BUG() during drop snapshot |
| |
| From: Josef Bacik <jbacik@fb.com> |
| |
| commit 4867268c57ff709a7b6b86ae6f6537d846d1443a upstream. |
| |
| Really there's lots of things that can go wrong here, kill all the |
| BUG_ON()'s and replace the logic ones with ASSERT()'s and return EIO |
| instead. |
| |
| Signed-off-by: Josef Bacik <jbacik@fb.com> |
| [ switched to btrfs_err, errors go to common label ] |
| Reviewed-by: Liu Bo <bo.li.liu@oracle.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/extent-tree.c | 38 +++++++++++++++++++++++++++----------- |
| 1 file changed, 27 insertions(+), 11 deletions(-) |
| |
| --- a/fs/btrfs/extent-tree.c |
| +++ b/fs/btrfs/extent-tree.c |
| @@ -8884,15 +8884,13 @@ static noinline int do_walk_down(struct |
| ret = btrfs_lookup_extent_info(trans, root, bytenr, level - 1, 1, |
| &wc->refs[level - 1], |
| &wc->flags[level - 1]); |
| - if (ret < 0) { |
| - btrfs_tree_unlock(next); |
| - free_extent_buffer(next); |
| - return ret; |
| - } |
| + if (ret < 0) |
| + goto out_unlock; |
| |
| if (unlikely(wc->refs[level - 1] == 0)) { |
| btrfs_err(root->fs_info, "Missing references."); |
| - BUG(); |
| + ret = -EIO; |
| + goto out_unlock; |
| } |
| *lookup_info = 0; |
| |
| @@ -8944,7 +8942,12 @@ static noinline int do_walk_down(struct |
| } |
| |
| level--; |
| - BUG_ON(level != btrfs_header_level(next)); |
| + ASSERT(level == btrfs_header_level(next)); |
| + if (level != btrfs_header_level(next)) { |
| + btrfs_err(root->fs_info, "mismatched level"); |
| + ret = -EIO; |
| + goto out_unlock; |
| + } |
| path->nodes[level] = next; |
| path->slots[level] = 0; |
| path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; |
| @@ -8959,8 +8962,15 @@ skip: |
| if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) { |
| parent = path->nodes[level]->start; |
| } else { |
| - BUG_ON(root->root_key.objectid != |
| + ASSERT(root->root_key.objectid == |
| btrfs_header_owner(path->nodes[level])); |
| + if (root->root_key.objectid != |
| + btrfs_header_owner(path->nodes[level])) { |
| + btrfs_err(root->fs_info, |
| + "mismatched block owner"); |
| + ret = -EIO; |
| + goto out_unlock; |
| + } |
| parent = 0; |
| } |
| |
| @@ -8977,12 +8987,18 @@ skip: |
| } |
| ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent, |
| root->root_key.objectid, level - 1, 0); |
| - BUG_ON(ret); /* -ENOMEM */ |
| + if (ret) |
| + goto out_unlock; |
| } |
| + |
| + *lookup_info = 1; |
| + ret = 1; |
| + |
| +out_unlock: |
| btrfs_tree_unlock(next); |
| free_extent_buffer(next); |
| - *lookup_info = 1; |
| - return 1; |
| + |
| + return ret; |
| } |
| |
| /* |