static int find_and_setup_root(struct btrfs_root *tree_root, struct btrfs_fs_info *fs_info, u64 objectid, struct btrfs_root *root) { int ret; u32 blocksize; u64 generation; __setup_root(tree_root->nodesize, tree_root->leafsize, tree_root->sectorsize, tree_root->stripesize, root, fs_info, objectid); ret = btrfs_find_last_root(tree_root, objectid, &root->root_item, &root->root_key); if (ret) return ret; blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); generation = btrfs_root_generation(&root->root_item); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); if (!extent_buffer_uptodate(root->node)) return -EIO; return 0; }
struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info, struct btrfs_key *location) { struct btrfs_root *root; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_path *path; struct extent_buffer *l; u64 generation; u32 blocksize; int ret = 0; root = malloc(sizeof(*root)); if (!root) return ERR_PTR(-ENOMEM); memset(root, 0, sizeof(*root)); if (location->offset == (u64)-1) { ret = find_and_setup_root(tree_root, fs_info, location->objectid, root); if (ret) { free(root); return ERR_PTR(ret); } goto insert; } __setup_root(tree_root->nodesize, tree_root->leafsize, tree_root->sectorsize, tree_root->stripesize, root, fs_info, location->objectid); path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); if (ret != 0) { if (ret > 0) ret = -ENOENT; goto out; } l = path->nodes[0]; read_extent_buffer(l, &root->root_item, btrfs_item_ptr_offset(l, path->slots[0]), sizeof(root->root_item)); memcpy(&root->root_key, location, sizeof(*location)); ret = 0; out: btrfs_release_path(root, path); btrfs_free_path(path); if (ret) { free(root); return ERR_PTR(ret); } generation = btrfs_root_generation(&root->root_item); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); BUG_ON(!root->node); insert: root->ref_cows = 1; return root; }
void unpack_root_item(struct gosafe_btrfs_root_item* dst, struct btrfs_root_item* src) { memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE); memcpy(dst->parent_uuid, src->parent_uuid, BTRFS_UUID_SIZE); memcpy(dst->received_uuid, src->received_uuid, BTRFS_UUID_SIZE); dst->gen = btrfs_root_generation(src); dst->ogen = btrfs_root_otransid(src); dst->flags = btrfs_root_flags(src); }
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); }
static void __recow_root(struct btrfs_trans_handle *trans, struct btrfs_root *root) { int ret; struct extent_buffer *tmp; if (trans->transid != btrfs_root_generation(&root->root_item)) { ret = __btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp, 0, 0); BUG_ON(ret); free_extent_buffer(tmp); } }
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); } }
/* finding the generation for a given path is a two step process. * First we use the inode loookup routine to find out the root id * * Then we use the tree search ioctl to scan all the root items for a * given root id and spit out the latest generation we can find */ static u64 find_root_gen(int fd) { struct btrfs_ioctl_ino_lookup_args ino_args; int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; u64 max_found = 0; int i; int e; memset(&ino_args, 0, sizeof(ino_args)); ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID; /* this ioctl fills in ino_args->treeid */ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", (unsigned long long)BTRFS_FIRST_FREE_OBJECTID, strerror(e)); return 0; } memset(&args, 0, sizeof(args)); sk->tree_id = 1; /* * there may be more than one ROOT_ITEM key if there are * snapshots pending deletion, we have to loop through * them. */ sk->min_objectid = ino_args.treeid; sk->max_objectid = ino_args.treeid; sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 4096; while (1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return 0; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; for (i = 0; i < sk->nr_items; i++) { struct btrfs_root_item *item; sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); item = (struct btrfs_root_item *)(args.buf + off); off += sh->len; sk->min_objectid = sh->objectid; sk->min_type = sh->type; sk->min_offset = sh->offset; if (sh->objectid > ino_args.treeid) break; if (sh->objectid == ino_args.treeid && sh->type == BTRFS_ROOT_ITEM_KEY) { max_found = max(max_found, btrfs_root_generation(item)); } } if (sk->min_offset < (u64)-1) sk->min_offset++; else break; if (sk->min_type != BTRFS_ROOT_ITEM_KEY) break; if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY) break; } return max_found; }
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); } }