diff --git a/disk-io.c b/disk-io.c
index 71ca31f..6673a99 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -35,6 +35,7 @@
 #include "utils.h"
 #include "print-tree.h"
 #include "rbtree-utils.h"
+#include "find-root.h"
 
 static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 {
@@ -894,9 +895,33 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
 	blocksize = btrfs_level_size(root, btrfs_super_root_level(sb));
 	generation = btrfs_super_generation(sb);
 
-	if (!root_tree_bytenr && !(flags & OPEN_CTREE_BACKUP_ROOT)) {
+	/*
+	 * If root bytenr is specified, use it and if fails, just return error,
+	 * not to try other method.
+	 */
+	if (root_tree_bytenr) {
+		root->node = read_tree_block(root, root_tree_bytenr,
+					     blocksize, generation);
+		if (!extent_buffer_uptodate(root->node)) {
+			fprintf(stderr, "Couldn't read tree root at %llu\n",
+				root_tree_bytenr);
+			return -EIO;
+		} else
+			goto extent_tree;
+	}
+	/* Normal root bytenr from super */
+	if (!(flags & OPEN_CTREE_BACKUP_ROOT)) {
 		root_tree_bytenr = btrfs_super_root(sb);
-	} else if (flags & OPEN_CTREE_BACKUP_ROOT) {
+		root->node = read_tree_block(root, root_tree_bytenr,
+					     blocksize, generation);
+		if (!extent_buffer_uptodate(root->node)) {
+			fprintf(stderr,
+				"Couldn't read tree root, try backup\n");
+			ret = -EAGAIN;
+		} else
+			goto extent_tree;
+	}
+	if ((flags & OPEN_CTREE_BACKUP_ROOT) || ret == -EAGAIN) {
 		struct btrfs_root_backup *backup;
 		int index = find_best_backup_root(sb);
 		if (index >= BTRFS_NUM_BACKUP_ROOTS) {
@@ -906,15 +931,78 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
 		backup = fs_info->super_copy->super_roots + index;
 		root_tree_bytenr = btrfs_backup_tree_root(backup);
 		generation = btrfs_backup_tree_root_gen(backup);
+		root->node = read_tree_block(root, root_tree_bytenr,
+					     blocksize, generation);
+		if (!extent_buffer_uptodate(root->node)) {
+			fprintf(stderr,
+				"Couldn't read backup tree root, try searching tree root\n");
+			ret = -EAGAIN;
+		} else {
+			ret = 0;
+			goto extent_tree;
+		}
 	}
 
-	root->node = read_tree_block(root, root_tree_bytenr, blocksize,
-				     generation);
-	if (!extent_buffer_uptodate(root->node)) {
-		fprintf(stderr, "Couldn't read tree root\n");
-		return -EIO;
-	}
+	/* Last chance, search the tree root */
+	if (ret == -EAGAIN) {
+		struct btrfs_find_root_filter filter = {0};
+		struct btrfs_find_root_gen_cache *gen_cache;
+		struct cache_tree result;
+		struct cache_extent *cache;
+		struct cache_extent *tree_block;
+
+		filter.objectid = BTRFS_ROOT_TREE_OBJECTID;
+		cache_tree_init(&result);
+
+		printf("Searching tree root, may take some time\n");
+		ret = btrfs_find_root_search(fs_info->chunk_root, &filter,
+					     &result, NULL);
+		if (ret < 0) {
+			fprintf(stderr, "Couldn't search tree root: %s\n",
+				strerror(-ret));
+			btrfs_find_root_free(&result);
+			return ret;
+		}
+		if (cache_tree_empty(&result)) {
+			fprintf(stderr, "Fail to find any tree root\n");
+			btrfs_find_root_free(&result);
+			return -ENOENT;
+		}
 
+		/* Find the newest root as tree root */
+		root_tree_bytenr = 0;
+		cache = last_cache_extent(&result);
+		while (cache) {
+			gen_cache = container_of(cache,
+					struct btrfs_find_root_gen_cache,
+					cache);
+			if (last_cache_extent(&gen_cache->eb_tree) !=
+			    first_cache_extent(&gen_cache->eb_tree)) {
+				cache = prev_cache_extent(cache);
+				continue;
+			}
+			tree_block = first_cache_extent(&gen_cache->eb_tree);
+			root_tree_bytenr = tree_block->start;
+			generation = gen_cache->cache.start;
+			break;
+		}
+		btrfs_find_root_free(&result);
+		if (!root_tree_bytenr) {
+			fprintf(stderr,
+				"Couldn't find any valid old tree root\n");
+			return -EINVAL;
+		} else
+			printf("Using tree root at %llu, gen: %llu\n",
+			       root_tree_bytenr, generation);
+		root->node = read_tree_block(root, root_tree_bytenr,
+					     blocksize, generation);
+		if (!extent_buffer_uptodate(root->node)) {
+			fprintf(stderr,
+				"Couldn't read the most possible tree root\n");
+			return -EIO;
+		}
+	}
+extent_tree:
 	ret = setup_root_or_create_block(fs_info, flags, fs_info->extent_root,
 					 BTRFS_EXTENT_TREE_OBJECTID, "extent");
 	if (ret)
