X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=btrfs-find-root.c;h=e2d2e70c408c94ce4b4e5f6eaf3e94584b803e2d;hb=4a5b95abb620175ca6eb356ff8a7d698891fa8ab;hp=9347b91f3832d44ec147cf29a7e5265cc8425fe5;hpb=a34d4eab3a37349ca9aa47b9e5545e5e2c6a7d3f;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/btrfs-find-root.c b/btrfs-find-root.c index 9347b91..e2d2e70 100644 --- a/btrfs-find-root.c +++ b/btrfs-find-root.c @@ -22,6 +22,8 @@ #include #include #include +#include + #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" @@ -33,250 +35,14 @@ #include "crc32c.h" #include "extent-cache.h" #include "find-root.h" +#include "help.h" -static u16 csum_size = 0; -static u64 search_objectid = BTRFS_ROOT_TREE_OBJECTID; -static u64 search_generation = 0; -static unsigned long search_level = 0; - -static void usage(void) +static void find_root_usage(void) { - fprintf(stderr, "Usage: find-roots [-o search_objectid] " + fprintf(stderr, "Usage: find-roots [-a] [-o search_objectid] " "[ -g search_generation ] [ -l search_level ] \n"); } -static int csum_block(void *buf, u32 len) -{ - char *result; - u32 crc = ~(u32)0; - int ret = 0; - - result = malloc(csum_size * sizeof(char)); - if (!result) { - fprintf(stderr, "No memory\n"); - return 1; - } - - len -= BTRFS_CSUM_SIZE; - crc = crc32c(crc, buf + BTRFS_CSUM_SIZE, len); - btrfs_csum_final(crc, result); - - if (memcmp(buf, result, csum_size)) - ret = 1; - free(result); - return ret; -} - -static struct btrfs_root *open_ctree_broken(int fd, const char *device) -{ - struct btrfs_fs_info *fs_info; - struct btrfs_super_block *disk_super; - struct btrfs_fs_devices *fs_devices = NULL; - struct extent_buffer *eb; - int ret; - - fs_info = btrfs_new_fs_info(0, BTRFS_SUPER_INFO_OFFSET); - if (!fs_info) { - fprintf(stderr, "Failed to allocate memory for fs_info\n"); - return NULL; - } - - ret = btrfs_scan_fs_devices(fd, device, &fs_devices, 0, 1, 0); - if (ret) - goto out; - - fs_info->fs_devices = fs_devices; - - ret = btrfs_open_devices(fs_devices, O_RDONLY); - if (ret) - goto out_devices; - - disk_super = fs_info->super_copy; - ret = btrfs_read_dev_super(fs_devices->latest_bdev, - disk_super, fs_info->super_bytenr, 1); - if (ret) { - printk("No valid btrfs found\n"); - goto out_devices; - } - - memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE); - - ret = btrfs_check_fs_compatibility(disk_super, 0); - if (ret) - goto out_devices; - - ret = btrfs_setup_chunk_tree_and_device_map(fs_info); - if (ret) - goto out_chunk; - - eb = fs_info->chunk_root->node; - read_extent_buffer(eb, fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(eb), BTRFS_UUID_SIZE); - - return fs_info->chunk_root; -out_chunk: - free_extent_buffer(fs_info->chunk_root->node); - btrfs_cleanup_all_caches(fs_info); -out_devices: - btrfs_close_devices(fs_info->fs_devices); -out: - btrfs_free_fs_info(fs_info); - return NULL; -} - -static int search_iobuf(struct btrfs_root *root, void *iobuf, - size_t iobuf_size, off_t offset) -{ - u64 gen = search_generation; - u64 objectid = search_objectid; - u32 size = btrfs_super_nodesize(root->fs_info->super_copy); - u8 level = search_level; - size_t block_off = 0; - - while (block_off < iobuf_size) { - void *block = iobuf + block_off; - struct btrfs_header *header = block; - u64 h_byte, h_level, h_gen, h_owner; - -// printf("searching %Lu\n", offset + block_off); - h_byte = btrfs_stack_header_bytenr(header); - h_owner = btrfs_stack_header_owner(header); - h_level = header->level; - h_gen = btrfs_stack_header_generation(header); - - if (h_owner != objectid) - goto next; - if (h_byte != (offset + block_off)) - goto next; - if (h_level < level) - goto next; - level = h_level; - if (csum_block(block, size)) { - fprintf(stderr, "Well block %Lu seems good, " - "but the csum doesn't match\n", - h_byte); - goto next; - } - if (h_gen != gen) { - fprintf(stderr, "Well block %Lu seems great, " - "but generation doesn't match, " - "have=%Lu, want=%Lu level %Lu\n", h_byte, - h_gen, gen, h_level); - goto next; - } - printf("Found tree root at %Lu gen %Lu level %Lu\n", h_byte, - h_gen, h_level); - return 0; -next: - block_off += size; - } - - return 1; -} - -static int read_physical(struct btrfs_root *root, int fd, u64 offset, - u64 bytenr, u64 len) -{ - char *iobuf = malloc(len); - ssize_t done; - size_t total_read = 0; - int ret = 1; - - if (!iobuf) { - fprintf(stderr, "No memory\n"); - return -1; - } - - while (total_read < len) { - done = pread64(fd, iobuf + total_read, len - total_read, - bytenr + total_read); - if (done < 0) { - fprintf(stderr, "Failed to read: %s\n", - strerror(errno)); - ret = -1; - goto out; - } - total_read += done; - } - - ret = search_iobuf(root, iobuf, total_read, offset); -out: - free(iobuf); - return ret; -} - -static int find_root(struct btrfs_root *root) -{ - struct btrfs_multi_bio *multi = NULL; - struct btrfs_device *device; - u64 metadata_offset = 0, metadata_size = 0; - off_t offset = 0; - off_t bytenr; - int fd; - int err; - int ret = 1; - - printf("Super think's the tree root is at %Lu, chunk root %Lu\n", - btrfs_super_root(root->fs_info->super_copy), - btrfs_super_chunk_root(root->fs_info->super_copy)); - - err = btrfs_next_metadata(&root->fs_info->mapping_tree, - &metadata_offset, &metadata_size); - if (err) - return ret; - - offset = metadata_offset; - while (1) { - u64 map_length = 4096; - u64 type; - - if (offset > - btrfs_super_total_bytes(root->fs_info->super_copy)) { - printf("Went past the fs size, exiting"); - break; - } - if (offset >= (metadata_offset + metadata_size)) { - err = btrfs_next_metadata(&root->fs_info->mapping_tree, - &metadata_offset, - &metadata_size); - if (err) { - printf("No more metdata to scan, exiting\n"); - break; - } - offset = metadata_offset; - } - err = __btrfs_map_block(&root->fs_info->mapping_tree, READ, - offset, &map_length, &type, - &multi, 0, NULL); - if (err) { - offset += map_length; - continue; - } - - if (!(type & BTRFS_BLOCK_GROUP_METADATA)) { - offset += map_length; - kfree(multi); - continue; - } - - device = multi->stripes[0].dev; - fd = device->fd; - bytenr = multi->stripes[0].physical; - kfree(multi); - - err = read_physical(root, fd, offset, bytenr, map_length); - if (!err) { - ret = 0; - break; - } else if (err < 0) { - ret = err; - break; - } - offset += map_length; - } - return ret; -} - /* * Get reliable generation and level for given root. * @@ -304,7 +70,6 @@ static void get_root_gen_and_level(u64 objectid, struct btrfs_fs_info *fs_info, case BTRFS_CHUNK_TREE_OBJECTID: level = btrfs_super_chunk_root_level(super); gen = btrfs_super_chunk_root_generation(super); - printf("Search for chunk root is not supported yet\n"); break; case BTRFS_TREE_LOG_OBJECTID: level = btrfs_super_log_root_level(super); @@ -344,6 +109,9 @@ static void print_one_result(struct cache_extent *tree_block, tree_block->start, generation, level); if (unsure) printf("but we are unsure about the correct generation/level\n"); + else if (level == filter->match_level && + generation == filter->match_gen) + printf("and it matches superblock\n"); else printf("but generation/level doesn't match, want gen: %llu level: %u\n", filter->match_gen, filter->match_level); @@ -364,8 +132,10 @@ static void print_find_root_result(struct cache_tree *result, struct btrfs_find_root_gen_cache, cache); level = gen_cache->highest_level; generation = cache->start; + /* For exact found one, skip it as it's output before */ if (level == filter->match_level && - generation == filter->match_gen) + generation == filter->match_gen && + !filter->search_all) continue; for (tree_block = last_cache_extent(&gen_cache->eb_tree); tree_block; tree_block = prev_cache_extent(tree_block)) @@ -375,51 +145,64 @@ static void print_find_root_result(struct cache_tree *result, int main(int argc, char **argv) { - struct btrfs_root *root; + struct btrfs_fs_info *fs_info; struct btrfs_find_root_filter filter = {0}; struct cache_tree result; struct cache_extent *found; - int opt; int ret; /* Default to search root tree */ filter.objectid = BTRFS_ROOT_TREE_OBJECTID; filter.match_gen = (u64)-1; filter.match_level = (u8)-1; - while ((opt = getopt(argc, argv, "l:o:g:")) != -1) { - switch(opt) { - case 'o': - filter.objectid = arg_strtou64(optarg); - break; - case 'g': - filter.generation = arg_strtou64(optarg); - break; - case 'l': - filter.level = arg_strtou64(optarg); - break; - default: - usage(); - exit(1); + while (1) { + static const struct option long_options[] = { + { "help", no_argument, NULL, GETOPT_VAL_HELP}, + { NULL, 0, NULL, 0 } + }; + int c = getopt_long(argc, argv, "al:o:g:", long_options, NULL); + + if (c < 0) + break; + + switch (c) { + case 'a': + filter.search_all = 1; + break; + case 'o': + filter.objectid = arg_strtou64(optarg); + break; + case 'g': + filter.generation = arg_strtou64(optarg); + break; + case 'l': + filter.level = arg_strtou64(optarg); + break; + case GETOPT_VAL_HELP: + default: + find_root_usage(); + exit(c != GETOPT_VAL_HELP); } } set_argv0(argv); - argc = argc - optind; - if (check_argc_min(argc, 1)) { - usage(); + if (check_argc_min(argc - optind, 1)) { + find_root_usage(); exit(1); } - root = open_ctree(argv[optind], 0, OPEN_CTREE_CHUNK_ROOT_ONLY); - if (!root) { - fprintf(stderr, "Open ctree failed\n"); + fs_info = open_ctree_fs_info(argv[optind], 0, 0, 0, + OPEN_CTREE_CHUNK_ROOT_ONLY | + OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR); + if (!fs_info) { + error("open ctree failed"); exit(1); } cache_tree_init(&result); - get_root_gen_and_level(filter.objectid, root->fs_info, + get_root_gen_and_level(filter.objectid, fs_info, &filter.match_gen, &filter.match_level); - ret = btrfs_find_root_search(root, &filter, &result, &found); + ret = btrfs_find_root_search(fs_info, &filter, &result, &found); if (ret < 0) { fprintf(stderr, "Fail to search the tree root: %s\n", strerror(-ret)); @@ -433,6 +216,7 @@ int main(int argc, char **argv) print_find_root_result(&result, &filter); out: btrfs_find_root_free(&result); - close_ctree(root); + close_ctree_fs_info(fs_info); + btrfs_close_all_devices(); return ret; }