void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow) { int i; u32 nr; u32 size; struct btrfs_disk_key disk_key; struct btrfs_key key; if (!eb) return; nr = btrfs_header_nritems(eb); if (btrfs_is_leaf(eb)) { btrfs_print_leaf(root, eb); return; } printf("node %llu level %d items %d free %u generation %llu owner %llu\n", (unsigned long long)eb->start, btrfs_header_level(eb), nr, (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr, (unsigned long long)btrfs_header_generation(eb), (unsigned long long)btrfs_header_owner(eb)); print_uuids(eb); fflush(stdout); size = btrfs_level_size(root, btrfs_header_level(eb) - 1); for (i = 0; i < nr; i++) { u64 blocknr = btrfs_node_blockptr(eb, i); btrfs_node_key(eb, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); printf("\t"); btrfs_print_key(&disk_key); printf(" block %llu (%llu) gen %llu\n", (unsigned long long)blocknr, (unsigned long long)blocknr / size, (unsigned long long)btrfs_node_ptr_generation(eb, i)); fflush(stdout); } if (!follow) return; for (i = 0; i < nr; i++) { struct extent_buffer *next = read_tree_block(root, btrfs_node_blockptr(eb, i), size, btrfs_node_ptr_generation(eb, i)); if (!next) { fprintf(stderr, "failed to read %llu in tree %llu\n", (unsigned long long)btrfs_node_blockptr(eb, i), (unsigned long long)btrfs_header_owner(eb)); continue; } if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) BUG(); if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) BUG(); btrfs_print_tree(root, next, 1); free_extent_buffer(next); } }
static void print_root(struct extent_buffer *leaf, int slot) { struct btrfs_root_item *ri; struct btrfs_root_item root_item; int len; char uuid_str[BTRFS_UUID_UNPARSED_SIZE]; char flags_str[32] = {0}; struct btrfs_key drop_key; ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); len = btrfs_item_size_nr(leaf, slot); memset(&root_item, 0, sizeof(root_item)); read_extent_buffer(leaf, &root_item, (unsigned long)ri, len); root_flags_to_str(btrfs_root_flags(&root_item), flags_str); printf("\t\tgeneration %llu root_dirid %llu bytenr %llu level %hhu refs %u\n", (unsigned long long)btrfs_root_generation(&root_item), (unsigned long long)btrfs_root_dirid(&root_item), (unsigned long long)btrfs_root_bytenr(&root_item), btrfs_root_level(&root_item), btrfs_root_refs(&root_item)); printf("\t\tlastsnap %llu byte_limit %llu bytes_used %llu flags 0x%llx(%s)\n", (unsigned long long)btrfs_root_last_snapshot(&root_item), (unsigned long long)btrfs_root_limit(&root_item), (unsigned long long)btrfs_root_used(&root_item), (unsigned long long)btrfs_root_flags(&root_item), flags_str); if (root_item.generation == root_item.generation_v2) { uuid_unparse(root_item.uuid, uuid_str); printf("\t\tuuid %s\n", uuid_str); if (!empty_uuid(root_item.parent_uuid)) { uuid_unparse(root_item.parent_uuid, uuid_str); printf("\t\tparent_uuid %s\n", uuid_str); } if (!empty_uuid(root_item.received_uuid)) { uuid_unparse(root_item.received_uuid, uuid_str); printf("\t\treceived_uuid %s\n", uuid_str); } if (root_item.ctransid) { printf("\t\tctransid %llu otransid %llu stransid %llu rtransid %llu\n", btrfs_root_ctransid(&root_item), btrfs_root_otransid(&root_item), btrfs_root_stransid(&root_item), btrfs_root_rtransid(&root_item)); } } btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress); printf("\t\tdrop "); btrfs_print_key(&root_item.drop_progress); printf(" level %hhu\n", root_item.drop_level); }
int btrfs_read_block_groups(struct btrfs_root *root) { struct btrfs_path path; int ret; int err = 0; struct btrfs_block_group_item *bi; struct btrfs_block_group_cache *cache; struct btrfs_key key; struct btrfs_key found_key; struct btrfs_leaf *leaf; u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; root = root->fs_info->extent_root; key.objectid = 0; key.offset = group_size_blocks; key.flags = 0; btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY); btrfs_init_path(&path); while(1) { ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, &path, 0, 0); if (ret != 0) { err = ret; break; } leaf = &path.nodes[0]->leaf; btrfs_disk_key_to_cpu(&found_key, &leaf->items[path.slots[0]].key); cache = malloc(sizeof(*cache)); if (!cache) { err = -1; break; } bi = btrfs_item_ptr(leaf, path.slots[0], struct btrfs_block_group_item); memcpy(&cache->item, bi, sizeof(*bi)); memcpy(&cache->key, &found_key, sizeof(found_key)); key.objectid = found_key.objectid + found_key.offset; btrfs_release_path(root, &path); ret = radix_tree_insert(&root->fs_info->block_group_radix, found_key.objectid + found_key.offset - 1, (void *)cache); BUG_ON(ret); if (key.objectid >= btrfs_super_total_blocks(root->fs_info->disk_super)) break; } btrfs_release_path(root, &path); return 0; }
static void print_root(struct extent_buffer *leaf, int slot) { struct btrfs_root_item *ri; struct btrfs_root_item root_item; int len; char uuid_str[128]; ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); len = btrfs_item_size_nr(leaf, slot); memset(&root_item, 0, sizeof(root_item)); read_extent_buffer(leaf, &root_item, (unsigned long)ri, len); printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n", (unsigned long long)btrfs_root_bytenr(&root_item), btrfs_root_level(&root_item), (unsigned long long)btrfs_root_dirid(&root_item), btrfs_root_refs(&root_item), (unsigned long long)btrfs_root_generation(&root_item)); if (root_item.generation == root_item.generation_v2) { uuid_unparse(root_item.uuid, uuid_str); printf("\t\tuuid %s\n", uuid_str); if (count_bytes(root_item.parent_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) { uuid_unparse(root_item.parent_uuid, uuid_str); printf("\t\tparent_uuid %s\n", uuid_str); } if (count_bytes(root_item.received_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) { uuid_unparse(root_item.received_uuid, uuid_str); printf("\t\treceived_uuid %s\n", uuid_str); } if (root_item.ctransid) { printf("\t\tctransid %llu otransid %llu stransid %llu rtransid %llu\n", btrfs_root_ctransid(&root_item), btrfs_root_otransid(&root_item), btrfs_root_stransid(&root_item), btrfs_root_rtransid(&root_item)); } } if (btrfs_root_refs(&root_item) == 0) { struct btrfs_key drop_key; btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress); printf("\t\tdrop "); btrfs_print_key(&root_item.drop_progress); printf(" level %d\n", root_item.drop_level); } }
static void print_sys_chunk_array(struct btrfs_super_block *sb) { struct extent_buffer *buf; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; u8 *array_ptr; unsigned long sb_array_offset; u32 num_stripes; u32 array_size; u32 len = 0; u32 cur_offset; struct btrfs_key key; int item; buf = malloc(sizeof(*buf) + sizeof(*sb)); if (!buf) { fprintf(stderr, "%s\n", strerror(ENOMEM)); exit(1); } write_extent_buffer(buf, sb, 0, sizeof(*sb)); array_size = btrfs_super_sys_array_size(sb); array_ptr = sb->sys_chunk_array; sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array); cur_offset = 0; item = 0; while (cur_offset < array_size) { disk_key = (struct btrfs_disk_key *)array_ptr; len = sizeof(*disk_key); if (cur_offset + len > array_size) goto out_short_read; btrfs_disk_key_to_cpu(&key, disk_key); array_ptr += len; sb_array_offset += len; cur_offset += len; printf("\titem %d ", item); btrfs_print_key(disk_key); putchar('\n'); if (key.type == BTRFS_CHUNK_ITEM_KEY) { chunk = (struct btrfs_chunk *)sb_array_offset; /* * At least one btrfs_chunk with one stripe must be * present, exact stripe count check comes afterwards */ len = btrfs_chunk_item_size(1); if (cur_offset + len > array_size) goto out_short_read; print_chunk(buf, chunk); num_stripes = btrfs_chunk_num_stripes(buf, chunk); if (!num_stripes) { printk( "ERROR: invalid number of stripes %u in sys_array at offset %u\n", num_stripes, cur_offset); break; } len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size) goto out_short_read; } else { printk( "ERROR: unexpected item type %u in sys_array at offset %u\n", (u32)key.type, cur_offset); break; } array_ptr += len; sb_array_offset += len; cur_offset += len; item++; } free(buf); return; out_short_read: printk("ERROR: sys_array too short to read %u bytes at offset %u\n", len, cur_offset); free(buf); }
/* * add all currently queued delayed refs from this head whose seq nr is * smaller or equal that seq to the list */ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, struct list_head *prefs) { struct btrfs_delayed_extent_op *extent_op = head->extent_op; struct rb_node *n = &head->node.rb_node; struct btrfs_key key; struct btrfs_key op_key = {0}; int sgn; int ret = 0; if (extent_op && extent_op->update_key) btrfs_disk_key_to_cpu(&op_key, &extent_op->key); while ((n = rb_prev(n))) { struct btrfs_delayed_ref_node *node; node = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); if (node->bytenr != head->node.bytenr) break; WARN_ON(node->is_head); if (node->seq > seq) continue; switch (node->action) { case BTRFS_ADD_DELAYED_EXTENT: case BTRFS_UPDATE_DELAYED_HEAD: WARN_ON(1); continue; case BTRFS_ADD_DELAYED_REF: sgn = 1; break; case BTRFS_DROP_DELAYED_REF: sgn = -1; break; default: BUG_ON(1); } switch (node->type) { case BTRFS_TREE_BLOCK_REF_KEY: { struct btrfs_delayed_tree_ref *ref; ref = btrfs_delayed_node_to_tree_ref(node); ret = __add_prelim_ref(prefs, ref->root, &op_key, ref->level + 1, 0, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_SHARED_BLOCK_REF_KEY: { struct btrfs_delayed_tree_ref *ref; ref = btrfs_delayed_node_to_tree_ref(node); ret = __add_prelim_ref(prefs, ref->root, NULL, ref->level + 1, ref->parent, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_EXTENT_DATA_REF_KEY: { struct btrfs_delayed_data_ref *ref; ref = btrfs_delayed_node_to_data_ref(node); key.objectid = ref->objectid; key.type = BTRFS_EXTENT_DATA_KEY; key.offset = ref->offset; ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_SHARED_DATA_REF_KEY: { struct btrfs_delayed_data_ref *ref; ref = btrfs_delayed_node_to_data_ref(node); key.objectid = ref->objectid; key.type = BTRFS_EXTENT_DATA_KEY; key.offset = ref->offset; ret = __add_prelim_ref(prefs, ref->root, &key, 0, ref->parent, node->bytenr, node->ref_mod * sgn); break; } default: WARN_ON(1); } if (ret) return ret; } return 0; }
int main(int ac, char **av) { struct btrfs_root *root; struct btrfs_fs_info *info; struct btrfs_path path; struct btrfs_key key; struct btrfs_root_item ri; struct extent_buffer *leaf; struct btrfs_disk_key disk_key; struct btrfs_key found_key; char uuidbuf[BTRFS_UUID_UNPARSED_SIZE]; int ret; int slot; int extent_only = 0; int device_only = 0; int uuid_tree_only = 0; int roots_only = 0; int root_backups = 0; u64 block_only = 0; struct btrfs_root *tree_root_scan; u64 tree_id = 0; radix_tree_init(); while(1) { int c; static const struct option long_options[] = { { "help", no_argument, NULL, GETOPT_VAL_HELP}, { NULL, 0, NULL, 0 } }; c = getopt_long(ac, av, "deb:rRut:", long_options, NULL); if (c < 0) break; switch(c) { case 'e': extent_only = 1; break; case 'd': device_only = 1; break; case 'r': roots_only = 1; break; case 'u': uuid_tree_only = 1; break; case 'R': roots_only = 1; root_backups = 1; break; case 'b': block_only = arg_strtou64(optarg); break; case 't': tree_id = arg_strtou64(optarg); break; case GETOPT_VAL_HELP: default: print_usage(c != GETOPT_VAL_HELP); } } set_argv0(av); ac = ac - optind; if (check_argc_exact(ac, 1)) print_usage(1); ret = check_arg_type(av[optind]); if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) { fprintf(stderr, "'%s' is not a block device or regular file\n", av[optind]); exit(1); } info = open_ctree_fs_info(av[optind], 0, 0, OPEN_CTREE_PARTIAL); if (!info) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); } root = info->fs_root; if (!root) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); } if (block_only) { leaf = read_tree_block(root, block_only, root->leafsize, 0); if (extent_buffer_uptodate(leaf) && btrfs_header_level(leaf) != 0) { free_extent_buffer(leaf); leaf = NULL; } if (!leaf) { leaf = read_tree_block(root, block_only, root->nodesize, 0); } if (!extent_buffer_uptodate(leaf)) { fprintf(stderr, "failed to read %llu\n", (unsigned long long)block_only); goto close_root; } btrfs_print_tree(root, leaf, 0); free_extent_buffer(leaf); goto close_root; } if (!(extent_only || uuid_tree_only || tree_id)) { if (roots_only) { printf("root tree: %llu level %d\n", (unsigned long long)info->tree_root->node->start, btrfs_header_level(info->tree_root->node)); printf("chunk tree: %llu level %d\n", (unsigned long long)info->chunk_root->node->start, btrfs_header_level(info->chunk_root->node)); } else { if (info->tree_root->node) { printf("root tree\n"); btrfs_print_tree(info->tree_root, info->tree_root->node, 1); } if (info->chunk_root->node) { printf("chunk tree\n"); btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1); } } } tree_root_scan = info->tree_root; btrfs_init_path(&path); again: if (!extent_buffer_uptodate(tree_root_scan->node)) goto no_node; /* * Tree's that are not pointed by the tree of tree roots */ if (tree_id && tree_id == BTRFS_ROOT_TREE_OBJECTID) { if (!info->tree_root->node) { error("cannot print root tree, invalid pointer"); goto no_node; } printf("root tree\n"); btrfs_print_tree(info->tree_root, info->tree_root->node, 1); goto no_node; } if (tree_id && tree_id == BTRFS_CHUNK_TREE_OBJECTID) { if (!info->chunk_root->node) { error("cannot print chunk tree, invalid pointer"); goto no_node; } printf("chunk tree\n"); btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1); goto no_node; } key.offset = 0; key.objectid = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0); BUG_ON(ret < 0); while(1) { leaf = path.nodes[0]; slot = path.slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(tree_root_scan, &path); if (ret != 0) break; leaf = path.nodes[0]; slot = path.slots[0]; } btrfs_item_key(leaf, &disk_key, path.slots[0]); btrfs_disk_key_to_cpu(&found_key, &disk_key); if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) { unsigned long offset; struct extent_buffer *buf; int skip = extent_only | device_only | uuid_tree_only; offset = btrfs_item_ptr_offset(leaf, slot); read_extent_buffer(leaf, &ri, offset, sizeof(ri)); buf = read_tree_block(tree_root_scan, btrfs_root_bytenr(&ri), btrfs_level_size(tree_root_scan, btrfs_root_level(&ri)), 0); if (!extent_buffer_uptodate(buf)) goto next; if (tree_id && found_key.objectid != tree_id) { free_extent_buffer(buf); goto next; } switch(found_key.objectid) { case BTRFS_ROOT_TREE_OBJECTID: if (!skip) printf("root"); break; case BTRFS_EXTENT_TREE_OBJECTID: if (!device_only && !uuid_tree_only) skip = 0; if (!skip) printf("extent"); break; case BTRFS_CHUNK_TREE_OBJECTID: if (!skip) { printf("chunk"); } break; case BTRFS_DEV_TREE_OBJECTID: if (!uuid_tree_only) skip = 0; if (!skip) printf("device"); break; case BTRFS_FS_TREE_OBJECTID: if (!skip) { printf("fs"); } break; case BTRFS_ROOT_TREE_DIR_OBJECTID: skip = 0; printf("directory"); break; case BTRFS_CSUM_TREE_OBJECTID: if (!skip) { printf("checksum"); } break; case BTRFS_ORPHAN_OBJECTID: if (!skip) { printf("orphan"); } break; case BTRFS_TREE_LOG_OBJECTID: if (!skip) { printf("log"); } break; case BTRFS_TREE_LOG_FIXUP_OBJECTID: if (!skip) { printf("log fixup"); } break; case BTRFS_TREE_RELOC_OBJECTID: if (!skip) { printf("reloc"); } break; case BTRFS_DATA_RELOC_TREE_OBJECTID: if (!skip) { printf("data reloc"); } break; case BTRFS_EXTENT_CSUM_OBJECTID: if (!skip) { printf("extent checksum"); } break; case BTRFS_QUOTA_TREE_OBJECTID: if (!skip) { printf("quota"); } break; case BTRFS_UUID_TREE_OBJECTID: if (!extent_only && !device_only) skip = 0; if (!skip) printf("uuid"); break; case BTRFS_FREE_SPACE_TREE_OBJECTID: if (!skip) printf("free space"); break; case BTRFS_MULTIPLE_OBJECTIDS: if (!skip) { printf("multiple"); } break; default: if (!skip) { printf("file"); } } if (extent_only && !skip) { print_extents(tree_root_scan, buf); } else if (!skip) { printf(" tree "); btrfs_print_key(&disk_key); if (roots_only) { printf(" %llu level %d\n", (unsigned long long)buf->start, btrfs_header_level(buf)); } else { printf(" \n"); btrfs_print_tree(tree_root_scan, buf, 1); } } free_extent_buffer(buf); } next: path.slots[0]++; } no_node: btrfs_release_path(&path); if (tree_root_scan == info->tree_root && info->log_root_tree) { tree_root_scan = info->log_root_tree; goto again; } if (extent_only || device_only || uuid_tree_only) goto close_root; if (root_backups) print_old_roots(info->super_copy); printf("total bytes %llu\n", (unsigned long long)btrfs_super_total_bytes(info->super_copy)); printf("bytes used %llu\n", (unsigned long long)btrfs_super_bytes_used(info->super_copy)); uuidbuf[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0'; uuid_unparse(info->super_copy->fsid, uuidbuf); printf("uuid %s\n", uuidbuf); printf("%s\n", PACKAGE_STRING); close_root: ret = close_ctree(root); btrfs_close_all_devices(); return ret; }
int main(int ac, char **av) { struct btrfs_root *root; struct btrfs_fs_info *info; struct btrfs_path path; struct btrfs_key key; struct btrfs_root_item ri; struct extent_buffer *leaf; struct btrfs_disk_key disk_key; struct btrfs_key found_key; char uuidbuf[37]; int ret; int slot; int extent_only = 0; int device_only = 0; int roots_only = 0; int root_backups = 0; u64 block_only = 0; struct btrfs_root *tree_root_scan; radix_tree_init(); while(1) { int c; c = getopt(ac, av, "deb:rR"); if (c < 0) break; switch(c) { case 'e': extent_only = 1; break; case 'd': device_only = 1; break; case 'r': roots_only = 1; break; case 'R': roots_only = 1; root_backups = 1; break; case 'b': block_only = atoll(optarg); break; default: print_usage(); } } ac = ac - optind; if (ac != 1) print_usage(); info = open_ctree_fs_info(av[optind], 0, 0, 1); if (!info) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); } root = info->fs_root; if (block_only) { if (!root) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); } leaf = read_tree_block(root, block_only, root->leafsize, 0); if (leaf && btrfs_header_level(leaf) != 0) { free_extent_buffer(leaf); leaf = NULL; } if (!leaf) { leaf = read_tree_block(root, block_only, root->nodesize, 0); } if (!leaf) { fprintf(stderr, "failed to read %llu\n", (unsigned long long)block_only); return 0; } btrfs_print_tree(root, leaf, 0); return 0; } if (!extent_only) { if (roots_only) { printf("root tree: %llu level %d\n", (unsigned long long)info->tree_root->node->start, btrfs_header_level(info->tree_root->node)); printf("chunk tree: %llu level %d\n", (unsigned long long)info->chunk_root->node->start, btrfs_header_level(info->chunk_root->node)); } else { if (info->tree_root->node) { printf("root tree\n"); btrfs_print_tree(info->tree_root, info->tree_root->node, 1); } if (info->chunk_root->node) { printf("chunk tree\n"); btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1); } } } tree_root_scan = info->tree_root; btrfs_init_path(&path); again: if (!extent_buffer_uptodate(tree_root_scan->node)) goto no_node; key.offset = 0; key.objectid = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0); BUG_ON(ret < 0); while(1) { leaf = path.nodes[0]; slot = path.slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(tree_root_scan, &path); if (ret != 0) break; leaf = path.nodes[0]; slot = path.slots[0]; } btrfs_item_key(leaf, &disk_key, path.slots[0]); btrfs_disk_key_to_cpu(&found_key, &disk_key); if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) { unsigned long offset; struct extent_buffer *buf; int skip = extent_only | device_only; offset = btrfs_item_ptr_offset(leaf, slot); read_extent_buffer(leaf, &ri, offset, sizeof(ri)); buf = read_tree_block(tree_root_scan, btrfs_root_bytenr(&ri), btrfs_level_size(tree_root_scan, btrfs_root_level(&ri)), 0); if (!extent_buffer_uptodate(buf)) goto next; switch(found_key.objectid) { case BTRFS_ROOT_TREE_OBJECTID: if (!skip) printf("root"); break; case BTRFS_EXTENT_TREE_OBJECTID: if (!device_only) skip = 0; if (!extent_only && !device_only) printf("extent"); break; case BTRFS_CHUNK_TREE_OBJECTID: if (!skip) { printf("chunk"); } break; case BTRFS_DEV_TREE_OBJECTID: skip = 0; printf("device"); break; case BTRFS_FS_TREE_OBJECTID: if (!skip) { printf("fs"); } break; case BTRFS_ROOT_TREE_DIR_OBJECTID: skip = 0; printf("directory"); break; case BTRFS_CSUM_TREE_OBJECTID: if (!skip) { printf("checksum"); } break; case BTRFS_ORPHAN_OBJECTID: if (!skip) { printf("orphan"); } break; case BTRFS_TREE_LOG_OBJECTID: if (!skip) { printf("log"); } break; case BTRFS_TREE_LOG_FIXUP_OBJECTID: if (!skip) { printf("log fixup"); } break; case BTRFS_TREE_RELOC_OBJECTID: if (!skip) { printf("reloc"); } break; case BTRFS_DATA_RELOC_TREE_OBJECTID: if (!skip) { printf("data reloc"); } break; case BTRFS_EXTENT_CSUM_OBJECTID: if (!skip) { printf("extent checksum"); } break; case BTRFS_QUOTA_TREE_OBJECTID: if (!skip) { printf("quota"); } break; case BTRFS_MULTIPLE_OBJECTIDS: if (!skip) { printf("multiple"); } break; default: if (!skip) { printf("file"); } } if (extent_only && !skip) { print_extents(tree_root_scan, buf); } else if (!skip) { printf(" tree "); btrfs_print_key(&disk_key); if (roots_only) { printf(" %llu level %d\n", (unsigned long long)buf->start, btrfs_header_level(buf)); } else { printf(" \n"); btrfs_print_tree(tree_root_scan, buf, 1); } } } next: path.slots[0]++; } no_node: btrfs_release_path(root, &path); if (tree_root_scan == info->tree_root && info->log_root_tree) { tree_root_scan = info->log_root_tree; goto again; } if (extent_only || device_only) return 0; if (root_backups) print_old_roots(&info->super_copy); printf("total bytes %llu\n", (unsigned long long)btrfs_super_total_bytes(&info->super_copy)); printf("bytes used %llu\n", (unsigned long long)btrfs_super_bytes_used(&info->super_copy)); uuidbuf[36] = '\0'; uuid_unparse(info->super_copy.fsid, uuidbuf); printf("uuid %s\n", uuidbuf); printf("%s\n", BTRFS_BUILD_VERSION); return 0; }
static void print_sys_chunk_array(struct btrfs_super_block *sb) { struct extent_buffer *buf; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; u8 *array_ptr; unsigned long sb_array_offset; u32 num_stripes; u32 array_size; u32 len = 0; u32 cur_offset; struct btrfs_key key; int item; buf = malloc(sizeof(*buf) + sizeof(*sb)); if (!buf) { error("not enough memory"); return; } write_extent_buffer(buf, sb, 0, sizeof(*sb)); buf->len = sizeof(*sb); array_size = btrfs_super_sys_array_size(sb); array_ptr = sb->sys_chunk_array; sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array); if (array_size > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) { error("sys_array_size %u shouldn't exceed %u bytes", array_size, BTRFS_SYSTEM_CHUNK_ARRAY_SIZE); goto out; } cur_offset = 0; item = 0; while (cur_offset < array_size) { disk_key = (struct btrfs_disk_key *)array_ptr; len = sizeof(*disk_key); if (cur_offset + len > array_size) goto out_short_read; btrfs_disk_key_to_cpu(&key, disk_key); array_ptr += len; sb_array_offset += len; cur_offset += len; printf("\titem %d ", item); btrfs_print_key(disk_key); putchar('\n'); if (key.type == BTRFS_CHUNK_ITEM_KEY) { chunk = (struct btrfs_chunk *)sb_array_offset; /* * At least one btrfs_chunk with one stripe must be * present, exact stripe count check comes afterwards */ len = btrfs_chunk_item_size(1); if (cur_offset + len > array_size) goto out_short_read; num_stripes = btrfs_chunk_num_stripes(buf, chunk); if (!num_stripes) { error( "invalid number of stripes %u in sys_array at offset %u", num_stripes, cur_offset); break; } len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size) goto out_short_read; print_chunk_item(buf, chunk); } else { error("unexpected item type %u in sys_array at offset %u", (u32)key.type, cur_offset); break; } array_ptr += len; sb_array_offset += len; cur_offset += len; item++; } out: free(buf); return; out_short_read: error("sys_array too short to read %u bytes at offset %u", len, cur_offset); free(buf); }
int main(int ac, char **av) { struct btrfs_key ins; struct btrfs_key last = { (u64)-1, 0, 0}; char *buf; int i; int num; int ret; int run_size = 100000; int max_key = 100000000; int tree_size = 0; struct btrfs_path path; struct btrfs_super_block super; struct btrfs_root *root; struct btrfs_trans_handle *trans; buf = malloc(512); memset(buf, 0, 512); radix_tree_init(); root = open_ctree(av[1], &super); trans = btrfs_start_transaction(root, 1); srand(55); ins.flags = 0; btrfs_set_key_type(&ins, BTRFS_STRING_ITEM_KEY); for (i = 0; i < run_size; i++) { num = next_key(i, max_key); // num = i; sprintf(buf, "string-%d", num); if (i % 10000 == 0) fprintf(stderr, "insert %d:%d\n", num, i); ins.objectid = num; ins.offset = 0; ret = btrfs_insert_item(trans, root, &ins, buf, 512); if (!ret) tree_size++; if (i == run_size - 5) { btrfs_commit_transaction(trans, root, &super); } } close_ctree(root, &super); root = open_ctree(av[1], &super); printf("starting search\n"); srand(55); for (i = 0; i < run_size; i++) { num = next_key(i, max_key); ins.objectid = num; btrfs_init_path(&path); if (i % 10000 == 0) fprintf(stderr, "search %d:%d\n", num, i); ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0); if (ret) { btrfs_print_tree(root, root->node); printf("unable to find %d\n", num); exit(1); } btrfs_release_path(root, &path); } close_ctree(root, &super); root = open_ctree(av[1], &super); printf("node %p level %d total ptrs %d free spc %lu\n", root->node, btrfs_header_level(&root->node->node.header), btrfs_header_nritems(&root->node->node.header), BTRFS_NODEPTRS_PER_BLOCK(root) - btrfs_header_nritems(&root->node->node.header)); printf("all searches good, deleting some items\n"); i = 0; srand(55); for (i = 0 ; i < run_size/4; i++) { num = next_key(i, max_key); ins.objectid = num; btrfs_init_path(&path); ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1); if (!ret) { if (i % 10000 == 0) fprintf(stderr, "del %d:%d\n", num, i); ret = btrfs_del_item(trans, root, &path); if (ret != 0) BUG(); tree_size--; } btrfs_release_path(root, &path); } close_ctree(root, &super); root = open_ctree(av[1], &super); srand(128); for (i = 0; i < run_size; i++) { num = next_key(i, max_key); sprintf(buf, "string-%d", num); ins.objectid = num; if (i % 10000 == 0) fprintf(stderr, "insert %d:%d\n", num, i); ret = btrfs_insert_item(trans, root, &ins, buf, 512); if (!ret) tree_size++; } close_ctree(root, &super); root = open_ctree(av[1], &super); srand(128); printf("starting search2\n"); for (i = 0; i < run_size; i++) { num = next_key(i, max_key); ins.objectid = num; btrfs_init_path(&path); if (i % 10000 == 0) fprintf(stderr, "search %d:%d\n", num, i); ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0); if (ret) { btrfs_print_tree(root, root->node); printf("unable to find %d\n", num); exit(1); } btrfs_release_path(root, &path); } printf("starting big long delete run\n"); while(root->node && btrfs_header_nritems(&root->node->node.header) > 0) { struct btrfs_leaf *leaf; int slot; ins.objectid = (u64)-1; btrfs_init_path(&path); ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1); if (ret == 0) BUG(); leaf = &path.nodes[0]->leaf; slot = path.slots[0]; if (slot != btrfs_header_nritems(&leaf->header)) BUG(); while(path.slots[0] > 0) { path.slots[0] -= 1; slot = path.slots[0]; leaf = &path.nodes[0]->leaf; btrfs_disk_key_to_cpu(&last, &leaf->items[slot].key); if (tree_size % 10000 == 0) printf("big del %d:%d\n", tree_size, i); ret = btrfs_del_item(trans, root, &path); if (ret != 0) { printf("del_item returned %d\n", ret); BUG(); } tree_size--; } btrfs_release_path(root, &path); } /* printf("previous tree:\n"); btrfs_print_tree(root, root->commit_root); printf("map before commit\n"); btrfs_print_tree(root->extent_root, root->extent_root->node); */ btrfs_commit_transaction(trans, root, &super); printf("tree size is now %d\n", tree_size); printf("root %p commit root %p\n", root->node, root->commit_root); printf("map tree\n"); btrfs_print_tree(root->fs_info->extent_root, root->fs_info->extent_root->node); close_ctree(root, &super); return 0; }
/* * walks the btree of allocated extents and find a hole of a given size. * The key ins is changed to record the hole: * ins->objectid == block start * ins->flags = BTRFS_EXTENT_ITEM_KEY * ins->offset == number of blocks * Any available blocks before search_start are skipped. */ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *orig_root, u64 num_blocks, u64 search_start, u64 search_end, struct btrfs_key *ins) { struct btrfs_path path; struct btrfs_key key; int ret; u64 hole_size = 0; int slot = 0; u64 last_block = 0; u64 test_block; int start_found; struct btrfs_leaf *l; struct btrfs_root * root = orig_root->fs_info->extent_root; unsigned int total_needed = num_blocks; total_needed += (btrfs_header_level(&root->node->node.header) + 1) * 3; if (root->fs_info->last_insert.objectid > search_start) search_start = root->fs_info->last_insert.objectid; ins->flags = 0; btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); check_failed: btrfs_init_path(&path); ins->objectid = search_start; ins->offset = 0; start_found = 0; ret = btrfs_search_slot(trans, root, ins, &path, 0, 0); if (ret < 0) goto error; if (path.slots[0] > 0) path.slots[0]--; while (1) { l = &path.nodes[0]->leaf; slot = path.slots[0]; if (slot >= btrfs_header_nritems(&l->header)) { ret = btrfs_next_leaf(root, &path); if (ret == 0) continue; if (ret < 0) goto error; if (!start_found) { ins->objectid = search_start; ins->offset = (u64)-1 - search_start; start_found = 1; goto check_pending; } ins->objectid = last_block > search_start ? last_block : search_start; ins->offset = (u64)-1 - ins->objectid; goto check_pending; } btrfs_disk_key_to_cpu(&key, &l->items[slot].key); if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) goto next; if (key.objectid >= search_start) { if (start_found) { if (last_block < search_start) last_block = search_start; hole_size = key.objectid - last_block; if (hole_size > total_needed) { ins->objectid = last_block; ins->offset = hole_size; goto check_pending; } } } start_found = 1; last_block = key.objectid + key.offset; next: path.slots[0]++; } // FIXME -ENOSPC check_pending: /* we have to make sure we didn't find an extent that has already * been allocated by the map tree or the original allocation */ btrfs_release_path(root, &path); BUG_ON(ins->objectid < search_start); for (test_block = ins->objectid; test_block < ins->objectid + total_needed; test_block++) { if (radix_tree_lookup(&root->fs_info->pinned_radix, test_block)) { search_start = test_block + 1; goto check_failed; } } BUG_ON(root->fs_info->current_insert.offset); root->fs_info->current_insert.offset = total_needed - num_blocks; root->fs_info->current_insert.objectid = ins->objectid + num_blocks; root->fs_info->current_insert.flags = 0; root->fs_info->last_insert.objectid = ins->objectid; ins->offset = num_blocks; return 0; error: btrfs_release_path(root, &path); return ret; }
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow) { u32 i; u32 nr; u32 size; struct btrfs_disk_key disk_key; struct btrfs_key key; struct extent_buffer *next; if (!eb) return; nr = btrfs_header_nritems(eb); if (btrfs_is_leaf(eb)) { btrfs_print_leaf(root, eb); return; } printf("node %llu level %d items %d free %u generation %llu owner %llu\n", (unsigned long long)eb->start, btrfs_header_level(eb), nr, (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr, (unsigned long long)btrfs_header_generation(eb), (unsigned long long)btrfs_header_owner(eb)); print_uuids(eb); fflush(stdout); size = root->nodesize; for (i = 0; i < nr; i++) { u64 blocknr = btrfs_node_blockptr(eb, i); btrfs_node_key(eb, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); printf("\t"); btrfs_print_key(&disk_key); printf(" block %llu (%llu) gen %llu\n", (unsigned long long)blocknr, (unsigned long long)blocknr / size, (unsigned long long)btrfs_node_ptr_generation(eb, i)); fflush(stdout); } if (!follow) return; for (i = 0; i < nr; i++) { next = read_tree_block(root, btrfs_node_blockptr(eb, i), size, btrfs_node_ptr_generation(eb, i)); if (!extent_buffer_uptodate(next)) { fprintf(stderr, "failed to read %llu in tree %llu\n", (unsigned long long)btrfs_node_blockptr(eb, i), (unsigned long long)btrfs_header_owner(eb)); continue; } if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) { warning( "eb corrupted: item %d eb level %d next level %d, skipping the rest", i, btrfs_header_level(next), btrfs_header_level(eb)); goto out; } if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) { warning( "eb corrupted: item %d eb level %d next level %d, skipping the rest", i, btrfs_header_level(next), btrfs_header_level(eb)); goto out; } btrfs_print_tree(root, next, 1); free_extent_buffer(next); } return; out: free_extent_buffer(next); }
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; char *str; struct btrfs_item *item; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_block_group_item *bi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_inode_ref *iref; struct btrfs_dev_extent *dev_extent; struct btrfs_disk_key disk_key; struct btrfs_root_item root_item; struct btrfs_block_group_item bg_item; struct btrfs_dir_log_item *dlog; u32 nr = btrfs_header_nritems(l); u32 type; printf("leaf %llu items %d free space %d generation %llu owner %llu\n", (unsigned long long)btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l), (unsigned long long)btrfs_header_generation(l), (unsigned long long)btrfs_header_owner(l)); print_uuids(l); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(l, i); btrfs_item_key(l, &disk_key, i); type = btrfs_disk_key_type(&disk_key); printf("\titem %d ", i); btrfs_print_key(&disk_key); printf(" itemoff %d itemsize %d\n", btrfs_item_offset(l, item), btrfs_item_size(l, item)); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printf("\t\tinode generation %llu size %llu block group %llu mode %o links %u\n", (unsigned long long)btrfs_inode_generation(l, ii), (unsigned long long)btrfs_inode_size(l, ii), (unsigned long long)btrfs_inode_block_group(l,ii), btrfs_inode_mode(l, ii), btrfs_inode_nlink(l, ii)); break; case BTRFS_INODE_REF_KEY: iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref); print_inode_ref_item(l, item, iref); break; case BTRFS_DIR_ITEM_KEY: case BTRFS_DIR_INDEX_KEY: case BTRFS_XATTR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l, item, di); break; case BTRFS_DIR_LOG_INDEX_KEY: case BTRFS_DIR_LOG_ITEM_KEY: dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item); printf("\t\tdir log end %Lu\n", (unsigned long long)btrfs_dir_log_end(l, dlog)); break; case BTRFS_ORPHAN_ITEM_KEY: printf("\t\torphan item\n"); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); read_extent_buffer(l, &root_item, (unsigned long)ri, sizeof(root_item)); printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n", (unsigned long long)btrfs_root_bytenr(&root_item), btrfs_root_level(&root_item), (unsigned long long)btrfs_root_dirid(&root_item), btrfs_root_refs(&root_item), (unsigned long long)btrfs_root_generation(&root_item)); if (btrfs_root_refs(&root_item) == 0) { struct btrfs_key drop_key; btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress); printf("\t\tdrop "); btrfs_print_key(&root_item.drop_progress); printf(" level %d\n", root_item.drop_level); } break; case BTRFS_ROOT_REF_KEY: print_root_ref(l, i, "ref"); break; case BTRFS_ROOT_BACKREF_KEY: print_root_ref(l, i, "backref"); break; case BTRFS_EXTENT_ITEM_KEY: print_extent_item(l, i); break; case BTRFS_TREE_BLOCK_REF_KEY: printf("\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); printf("\t\textent data backref root %llu " "objectid %llu offset %llu count %u\n", (unsigned long long)btrfs_extent_data_ref_root(l, dref), (unsigned long long)btrfs_extent_data_ref_objectid(l, dref), (unsigned long long)btrfs_extent_data_ref_offset(l, dref), btrfs_extent_data_ref_count(l, dref)); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printf("\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_CSUM_ITEM_KEY: printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_CSUM_KEY: printf("\t\textent csum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); print_file_extent_item(l, item, fi); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); read_extent_buffer(l, &bg_item, (unsigned long)bi, sizeof(bg_item)); printf("\t\tblock group used %llu chunk_objectid %llu flags %llu\n", (unsigned long long)btrfs_block_group_used(&bg_item), (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item), (unsigned long long)btrfs_block_group_flags(&bg_item)); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printf("\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", (unsigned long long) btrfs_dev_extent_chunk_tree(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_objectid(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_offset(l, dev_extent), (unsigned long long) btrfs_dev_extent_length(l, dev_extent)); break; case BTRFS_STRING_ITEM_KEY: /* dirty, but it's simple */ str = l->data + btrfs_item_ptr_offset(l, i); printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str); break; }; fflush(stdout); } }