]> git.hungrycats.org Git - linux/commitdiff
Btrfs: return gracefully from balance if fs tree is corrupted
authorLiu Bo <bo.li.liu@oracle.com>
Wed, 14 Sep 2016 15:51:46 +0000 (08:51 -0700)
committerZygo Blaxell <zblaxell@thirteen.furryterror.org>
Sat, 24 Sep 2016 04:14:17 +0000 (00:14 -0400)
When relocating tree blocks, we firstly get block information from
back references in the extent tree, we then search fs tree to try to
find all parents of a block.

However, if fs tree is corrupted, eg. if there're some missing
items, we could come across these WARN_ONs and BUG_ONs.

This makes us print some error messages and return gracefully
from balance.

Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
(cherry picked from commit ecc3b8e78e181e4769012e2a6ce3294307fdf766)

fs/btrfs/relocation.c

index 39e25b859808a3f11ab99d4b3ad475f58405f6e5..f1b6eae9a48a5b61f82614cce0ba66a05dbfc123 100644 (file)
@@ -922,9 +922,16 @@ again:
                        path2->slots[level]--;
 
                eb = path2->nodes[level];
-               WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) !=
-                       cur->bytenr);
-
+               if (btrfs_node_blockptr(eb, path2->slots[level]) !=
+                   cur->bytenr) {
+                       btrfs_err(root->fs_info,
+       "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
+                                 cur->bytenr, level - 1, root->objectid,
+                                 node_key->objectid, node_key->type,
+                                 node_key->offset);
+                       err = -ENOENT;
+                       goto out;
+               }
                lower = cur;
                need_check = true;
                for (; level < BTRFS_MAX_LEVEL; level++) {
@@ -2686,11 +2693,15 @@ static int do_relocation(struct btrfs_trans_handle *trans,
 
                if (!upper->eb) {
                        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-                       if (ret < 0) {
-                               err = ret;
+                       if (ret) {
+                               if (ret < 0)
+                                       err = ret;
+                               else
+                                       err = -ENOENT;
+
+                               btrfs_release_path(path);
                                break;
                        }
-                       BUG_ON(ret > 0);
 
                        if (!upper->eb) {
                                upper->eb = path->nodes[upper->level];