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.
19 #define _XOPEN_SOURCE 500
27 #include "kerncompat.h"
30 #include "print-tree.h"
31 #include "transaction.h"
38 static u16 csum_size
= 0;
39 static u64 search_objectid
= BTRFS_ROOT_TREE_OBJECTID
;
40 static u64 search_generation
= 0;
41 static unsigned long search_level
= 0;
43 static void usage(void)
45 fprintf(stderr
, "Usage: find-roots [-o search_objectid] "
46 "[ -g search_generation ] [ -l search_level ] <device>\n");
49 static int csum_block(void *buf
, u32 len
)
55 result
= malloc(csum_size
* sizeof(char));
57 fprintf(stderr
, "No memory\n");
61 len
-= BTRFS_CSUM_SIZE
;
62 crc
= crc32c(crc
, buf
+ BTRFS_CSUM_SIZE
, len
);
63 btrfs_csum_final(crc
, result
);
65 if (memcmp(buf
, result
, csum_size
))
71 static struct btrfs_root
*open_ctree_broken(int fd
, const char *device
)
73 struct btrfs_fs_info
*fs_info
;
74 struct btrfs_super_block
*disk_super
;
75 struct btrfs_fs_devices
*fs_devices
= NULL
;
76 struct extent_buffer
*eb
;
79 fs_info
= btrfs_new_fs_info(0, BTRFS_SUPER_INFO_OFFSET
);
81 fprintf(stderr
, "Failed to allocate memory for fs_info\n");
85 ret
= btrfs_scan_fs_devices(fd
, device
, &fs_devices
, 0, 1);
89 fs_info
->fs_devices
= fs_devices
;
91 ret
= btrfs_open_devices(fs_devices
, O_RDONLY
);
95 disk_super
= fs_info
->super_copy
;
96 ret
= btrfs_read_dev_super(fs_devices
->latest_bdev
,
97 disk_super
, fs_info
->super_bytenr
, 1);
99 printk("No valid btrfs found\n");
103 memcpy(fs_info
->fsid
, &disk_super
->fsid
, BTRFS_FSID_SIZE
);
105 ret
= btrfs_check_fs_compatibility(disk_super
, 0);
109 ret
= btrfs_setup_chunk_tree_and_device_map(fs_info
);
113 eb
= fs_info
->chunk_root
->node
;
114 read_extent_buffer(eb
, fs_info
->chunk_tree_uuid
,
115 btrfs_header_chunk_tree_uuid(eb
), BTRFS_UUID_SIZE
);
117 return fs_info
->chunk_root
;
119 free_extent_buffer(fs_info
->chunk_root
->node
);
120 btrfs_cleanup_all_caches(fs_info
);
122 btrfs_close_devices(fs_info
->fs_devices
);
124 btrfs_free_fs_info(fs_info
);
128 static int search_iobuf(struct btrfs_root
*root
, void *iobuf
,
129 size_t iobuf_size
, off_t offset
)
131 u64 gen
= search_generation
;
132 u64 objectid
= search_objectid
;
133 u32 size
= btrfs_super_nodesize(root
->fs_info
->super_copy
);
134 u8 level
= search_level
;
135 size_t block_off
= 0;
137 while (block_off
< iobuf_size
) {
138 void *block
= iobuf
+ block_off
;
139 struct btrfs_header
*header
= block
;
140 u64 h_byte
, h_level
, h_gen
, h_owner
;
142 // printf("searching %Lu\n", offset + block_off);
143 h_byte
= btrfs_stack_header_bytenr(header
);
144 h_owner
= btrfs_stack_header_owner(header
);
145 h_level
= header
->level
;
146 h_gen
= btrfs_stack_header_generation(header
);
148 if (h_owner
!= objectid
)
150 if (h_byte
!= (offset
+ block_off
))
155 if (csum_block(block
, size
)) {
156 fprintf(stderr
, "Well block %Lu seems good, "
157 "but the csum doesn't match\n",
162 fprintf(stderr
, "Well block %Lu seems great, "
163 "but generation doesn't match, "
164 "have=%Lu, want=%Lu level %Lu\n", h_byte
,
165 h_gen
, gen
, h_level
);
168 printf("Found tree root at %Lu gen %Lu level %Lu\n", h_byte
,
178 static int read_physical(struct btrfs_root
*root
, int fd
, u64 offset
,
181 char *iobuf
= malloc(len
);
183 size_t total_read
= 0;
187 fprintf(stderr
, "No memory\n");
191 while (total_read
< len
) {
192 done
= pread64(fd
, iobuf
+ total_read
, len
- total_read
,
193 bytenr
+ total_read
);
195 fprintf(stderr
, "Failed to read: %s\n",
203 ret
= search_iobuf(root
, iobuf
, total_read
, offset
);
209 static int find_root(struct btrfs_root
*root
)
211 struct btrfs_multi_bio
*multi
= NULL
;
212 struct btrfs_device
*device
;
213 u64 metadata_offset
= 0, metadata_size
= 0;
220 printf("Super think's the tree root is at %Lu, chunk root %Lu\n",
221 btrfs_super_root(root
->fs_info
->super_copy
),
222 btrfs_super_chunk_root(root
->fs_info
->super_copy
));
224 err
= btrfs_next_metadata(&root
->fs_info
->mapping_tree
,
225 &metadata_offset
, &metadata_size
);
229 offset
= metadata_offset
;
231 u64 map_length
= 4096;
235 btrfs_super_total_bytes(root
->fs_info
->super_copy
)) {
236 printf("Went past the fs size, exiting");
239 if (offset
>= (metadata_offset
+ metadata_size
)) {
240 err
= btrfs_next_metadata(&root
->fs_info
->mapping_tree
,
244 printf("No more metdata to scan, exiting\n");
247 offset
= metadata_offset
;
249 err
= __btrfs_map_block(&root
->fs_info
->mapping_tree
, READ
,
250 offset
, &map_length
, &type
,
253 offset
+= map_length
;
257 if (!(type
& BTRFS_BLOCK_GROUP_METADATA
)) {
258 offset
+= map_length
;
263 device
= multi
->stripes
[0].dev
;
265 bytenr
= multi
->stripes
[0].physical
;
268 err
= read_physical(root
, fd
, offset
, bytenr
, map_length
);
272 } else if (err
< 0) {
276 offset
+= map_length
;
281 int main(int argc
, char **argv
)
283 struct btrfs_root
*root
;
288 while ((opt
= getopt(argc
, argv
, "l:o:g:")) != -1) {
291 search_objectid
= arg_strtou64(optarg
);
294 search_generation
= arg_strtou64(optarg
);
297 search_level
= arg_strtou64(optarg
);
306 argc
= argc
- optind
;
307 if (check_argc_min(argc
, 1)) {
312 dev_fd
= open(argv
[optind
], O_RDONLY
);
314 fprintf(stderr
, "Failed to open device %s\n", argv
[optind
]);
318 root
= open_ctree_broken(dev_fd
, argv
[optind
]);
322 fprintf(stderr
, "Open ctree failed\n");
326 if (search_generation
== 0)
327 search_generation
= btrfs_super_generation(root
->fs_info
->super_copy
);
329 csum_size
= btrfs_super_csum_size(root
->fs_info
->super_copy
);
330 ret
= find_root(root
);