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
);
72 printf("Search for chunk root is not supported yet\n");
74 case BTRFS_TREE_LOG_OBJECTID
:
75 level
= btrfs_super_log_root_level(super
);
76 gen
= btrfs_super_log_root_transid(super
);
78 case BTRFS_UUID_TREE_OBJECTID
:
79 gen
= btrfs_super_uuid_tree_generation(super
);
83 printf("Superblock thinks the generation is %llu\n", gen
);
87 printf("Superblock doesn't contain generation info for root %llu\n",
90 if (level
!= (u8
)-1) {
91 printf("Superblock thinks the level is %u\n", level
);
95 printf("Superblock doesn't contain the level info for root %llu\n",
100 static void print_one_result(struct cache_extent
*tree_block
,
101 u8 level
, u64 generation
,
102 struct btrfs_find_root_filter
*filter
)
106 if (filter
->match_gen
== (u64
)-1 || filter
->match_level
== (u8
)-1)
108 printf("Well block %llu(gen: %llu level: %u) seems good, ",
109 tree_block
->start
, generation
, level
);
111 printf("but we are unsure about the correct generation/level\n");
112 else if (level
== filter
->match_level
&&
113 generation
== filter
->match_gen
)
114 printf("and it matches superblock\n");
116 printf("but generation/level doesn't match, want gen: %llu level: %u\n",
117 filter
->match_gen
, filter
->match_level
);
120 static void print_find_root_result(struct cache_tree
*result
,
121 struct btrfs_find_root_filter
*filter
)
123 struct btrfs_find_root_gen_cache
*gen_cache
;
124 struct cache_extent
*cache
;
125 struct cache_extent
*tree_block
;
129 for (cache
= last_cache_extent(result
);
130 cache
; cache
= prev_cache_extent(cache
)) {
131 gen_cache
= container_of(cache
,
132 struct btrfs_find_root_gen_cache
, cache
);
133 level
= gen_cache
->highest_level
;
134 generation
= cache
->start
;
135 /* For exact found one, skip it as it's output before */
136 if (level
== filter
->match_level
&&
137 generation
== filter
->match_gen
&&
140 for (tree_block
= last_cache_extent(&gen_cache
->eb_tree
);
141 tree_block
; tree_block
= prev_cache_extent(tree_block
))
142 print_one_result(tree_block
, level
, generation
, filter
);
146 int main(int argc
, char **argv
)
148 struct btrfs_root
*root
;
149 struct btrfs_find_root_filter filter
= {0};
150 struct cache_tree result
;
151 struct cache_extent
*found
;
154 /* Default to search root tree */
155 filter
.objectid
= BTRFS_ROOT_TREE_OBJECTID
;
156 filter
.match_gen
= (u64
)-1;
157 filter
.match_level
= (u8
)-1;
159 static const struct option long_options
[] = {
160 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
163 int c
= getopt_long(argc
, argv
, "al:o:g:", long_options
, NULL
);
170 filter
.search_all
= 1;
173 filter
.objectid
= arg_strtou64(optarg
);
176 filter
.generation
= arg_strtou64(optarg
);
179 filter
.level
= arg_strtou64(optarg
);
181 case GETOPT_VAL_HELP
:
184 exit(c
!= GETOPT_VAL_HELP
);
189 argc
= argc
- optind
;
190 if (check_argc_min(argc
, 1)) {
195 root
= open_ctree(argv
[optind
], 0, OPEN_CTREE_CHUNK_ROOT_ONLY
);
197 fprintf(stderr
, "Open ctree failed\n");
200 cache_tree_init(&result
);
202 get_root_gen_and_level(filter
.objectid
, root
->fs_info
,
203 &filter
.match_gen
, &filter
.match_level
);
204 ret
= btrfs_find_root_search(root
, &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
);
219 btrfs_close_all_devices();