2 * Copyright (C) 2011 Red Hat. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
27 #include "kerncompat.h"
30 #include "print-tree.h"
31 #include "transaction.h"
36 #include "extent-cache.h"
37 #include "find-root.h"
39 static void usage(void)
41 fprintf(stderr
, "Usage: find-roots [-a] [-o search_objectid] "
42 "[ -g search_generation ] [ -l search_level ] <device>\n");
46 * Get reliable generation and level for given root.
48 * We have two sources of gen/level: superblock and tree root.
49 * superblock include the following level:
51 * and the following generations:
53 * Other gen/leven can only be read from its btrfs_tree_root if possible.
55 * Currently we only believe things from superblock.
57 static void get_root_gen_and_level(u64 objectid
, struct btrfs_fs_info
*fs_info
,
58 u64
*ret_gen
, u8
*ret_level
)
60 struct btrfs_super_block
*super
= fs_info
->super_copy
;
65 case BTRFS_ROOT_TREE_OBJECTID
:
66 level
= btrfs_super_root_level(super
);
67 gen
= btrfs_super_generation(super
);
69 case BTRFS_CHUNK_TREE_OBJECTID
:
70 level
= btrfs_super_chunk_root_level(super
);
71 gen
= btrfs_super_chunk_root_generation(super
);
73 case BTRFS_TREE_LOG_OBJECTID
:
74 level
= btrfs_super_log_root_level(super
);
75 gen
= btrfs_super_log_root_transid(super
);
77 case BTRFS_UUID_TREE_OBJECTID
:
78 gen
= btrfs_super_uuid_tree_generation(super
);
82 printf("Superblock thinks the generation is %llu\n", gen
);
86 printf("Superblock doesn't contain generation info for root %llu\n",
89 if (level
!= (u8
)-1) {
90 printf("Superblock thinks the level is %u\n", level
);
94 printf("Superblock doesn't contain the level info for root %llu\n",
99 static void print_one_result(struct cache_extent
*tree_block
,
100 u8 level
, u64 generation
,
101 struct btrfs_find_root_filter
*filter
)
105 if (filter
->match_gen
== (u64
)-1 || filter
->match_level
== (u8
)-1)
107 printf("Well block %llu(gen: %llu level: %u) seems good, ",
108 tree_block
->start
, generation
, level
);
110 printf("but we are unsure about the correct generation/level\n");
111 else if (level
== filter
->match_level
&&
112 generation
== filter
->match_gen
)
113 printf("and it matches superblock\n");
115 printf("but generation/level doesn't match, want gen: %llu level: %u\n",
116 filter
->match_gen
, filter
->match_level
);
119 static void print_find_root_result(struct cache_tree
*result
,
120 struct btrfs_find_root_filter
*filter
)
122 struct btrfs_find_root_gen_cache
*gen_cache
;
123 struct cache_extent
*cache
;
124 struct cache_extent
*tree_block
;
128 for (cache
= last_cache_extent(result
);
129 cache
; cache
= prev_cache_extent(cache
)) {
130 gen_cache
= container_of(cache
,
131 struct btrfs_find_root_gen_cache
, cache
);
132 level
= gen_cache
->highest_level
;
133 generation
= cache
->start
;
134 /* For exact found one, skip it as it's output before */
135 if (level
== filter
->match_level
&&
136 generation
== filter
->match_gen
&&
139 for (tree_block
= last_cache_extent(&gen_cache
->eb_tree
);
140 tree_block
; tree_block
= prev_cache_extent(tree_block
))
141 print_one_result(tree_block
, level
, generation
, filter
);
145 int main(int argc
, char **argv
)
147 struct btrfs_fs_info
*fs_info
;
148 struct btrfs_find_root_filter filter
= {0};
149 struct cache_tree result
;
150 struct cache_extent
*found
;
153 /* Default to search root tree */
154 filter
.objectid
= BTRFS_ROOT_TREE_OBJECTID
;
155 filter
.match_gen
= (u64
)-1;
156 filter
.match_level
= (u8
)-1;
158 static const struct option long_options
[] = {
159 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
162 int c
= getopt_long(argc
, argv
, "al:o:g:", long_options
, NULL
);
169 filter
.search_all
= 1;
172 filter
.objectid
= arg_strtou64(optarg
);
175 filter
.generation
= arg_strtou64(optarg
);
178 filter
.level
= arg_strtou64(optarg
);
180 case GETOPT_VAL_HELP
:
183 exit(c
!= GETOPT_VAL_HELP
);
188 if (check_argc_min(argc
- optind
, 1)) {
193 fs_info
= open_ctree_fs_info(argv
[optind
], 0, 0, 0,
194 OPEN_CTREE_CHUNK_ROOT_ONLY
|
195 OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR
);
197 error("open ctree failed");
200 cache_tree_init(&result
);
202 get_root_gen_and_level(filter
.objectid
, fs_info
,
203 &filter
.match_gen
, &filter
.match_level
);
204 ret
= btrfs_find_root_search(fs_info
, &filter
, &result
, &found
);
206 fprintf(stderr
, "Fail to search the tree root: %s\n",
211 printf("Found tree root at %llu gen %llu level %u\n",
212 found
->start
, filter
.match_gen
, filter
.match_level
);
215 print_find_root_result(&result
, &filter
);
217 btrfs_find_root_free(&result
);
218 close_ctree_fs_info(fs_info
);
219 btrfs_close_all_devices();