From ad44d1eb171a5ec1766d11d020324040cb51a436 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.com>
Date: Tue, 6 Sep 2016 15:55:59 +0200
Subject: [PATCH] btrfs-progs: improved error handling in btrfs_print_tree

Signed-off-by: David Sterba <dsterba@suse.com>
---
 print-tree.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/print-tree.c b/print-tree.c
index f97482f3..4444a143 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -1148,6 +1148,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int fol
 	u32 size;
 	struct btrfs_disk_key disk_key;
 	struct btrfs_key key;
+	struct extent_buffer *next;
 
 	if (!eb)
 		return;
@@ -1181,23 +1182,34 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int fol
 		return;
 
 	for (i = 0; i < nr; i++) {
-		struct extent_buffer *next = read_tree_block(root,
-					     btrfs_node_blockptr(eb, i),
-					     size,
-					     btrfs_node_ptr_generation(eb, i));
+		next = read_tree_block(root, btrfs_node_blockptr(eb, i), size,
+				btrfs_node_ptr_generation(eb, i));
 		if (!extent_buffer_uptodate(next)) {
 			fprintf(stderr, "failed to read %llu in tree %llu\n",
 				(unsigned long long)btrfs_node_blockptr(eb, i),
 				(unsigned long long)btrfs_header_owner(eb));
 			continue;
 		}
-		if (btrfs_is_leaf(next) &&
-		    btrfs_header_level(eb) != 1)
-			BUG();
-		if (btrfs_header_level(next) !=
-			btrfs_header_level(eb) - 1)
-			BUG();
+		if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
+			warning(
+	"eb corrupted: item %d eb level %d next level %d, skipping the rest",
+				i, btrfs_header_level(next),
+				btrfs_header_level(eb));
+			goto out;
+		}
+		if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) {
+			warning(
+	"eb corrupted: item %d eb level %d next level %d, skipping the rest",
+				i, btrfs_header_level(next),
+				btrfs_header_level(eb));
+			goto out;
+		}
 		btrfs_print_tree(root, next, 1);
 		free_extent_buffer(next);
 	}
+
+	return;
+
+out:
+	free_extent_buffer(next);
 }