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_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 struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, u64 root_objectid, u32 generation, int check_generation) { struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_root *root; struct inode *inode; struct btrfs_key key; int index; int err = 0; if (objectid < BTRFS_FIRST_FREE_OBJECTID) return ERR_PTR(-ESTALE); key.objectid = root_objectid; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); key.offset = (u64)-1; index = srcu_read_lock(&fs_info->subvol_srcu); root = btrfs_read_fs_root_no_name(fs_info, &key); if (IS_ERR(root)) { err = PTR_ERR(root); goto fail; } if (btrfs_root_refs(&root->root_item) == 0) { err = -ENOENT; goto fail; } key.objectid = objectid; btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); key.offset = 0; inode = btrfs_iget(sb, &key, root, NULL); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto fail; } srcu_read_unlock(&fs_info->subvol_srcu, index); if (check_generation && generation != inode->i_generation) { iput(inode); return ERR_PTR(-ESTALE); } return d_obtain_alias(inode); fail: srcu_read_unlock(&fs_info->subvol_srcu, index); return ERR_PTR(err); }
/* * Create a new subvolume below @parent. This is largely modeled after * sys_mkdirat and vfs_mkdir, but we only do a single component lookup * inside this filesystem so it's quite a bit simpler. */ static noinline int btrfs_mksubvol(struct path *parent, char *name, int namelen, struct btrfs_root *snap_src) { struct inode *dir = parent->dentry->d_inode; struct dentry *dentry; int error; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(name, parent->dentry, namelen); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_unlock; error = -EEXIST; if (dentry->d_inode) goto out_dput; error = mnt_want_write(parent->mnt); if (error) goto out_dput; error = btrfs_may_create(dir, dentry); if (error) goto out_drop_write; down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) goto out_up_read; if (snap_src) { error = create_snapshot(snap_src, dentry, name, namelen); } else { error = create_subvol(BTRFS_I(dir)->root, dentry, name, namelen); } if (!error) fsnotify_mkdir(dir, dentry); out_up_read: up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); out_drop_write: mnt_drop_write(parent->mnt); out_dput: dput(dentry); out_unlock: mutex_unlock(&dir->i_mutex); return error; }
/* * at transaction commit time we need to schedule the old roots for * deletion via btrfs_drop_snapshot. This runs through all the * reference counted roots that were modified in the current * transaction and puts them into the drop list */ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, struct radix_tree_root *radix, struct list_head *list) { struct btrfs_dirty_root *dirty; struct btrfs_root *gang[8]; struct btrfs_root *root; int i; int ret; int err = 0; u32 refs; while (1) { ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0, ARRAY_SIZE(gang), BTRFS_ROOT_TRANS_TAG); if (ret == 0) break; for (i = 0; i < ret; i++) { root = gang[i]; radix_tree_tag_clear(radix, (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); BUG_ON(!root->ref_tree); dirty = root->dirty_root; btrfs_free_log(trans, root); btrfs_free_reloc_root(trans, root); if (root->commit_root == root->node) { WARN_ON(root->node->start != btrfs_root_bytenr(&root->root_item)); free_extent_buffer(root->commit_root); root->commit_root = NULL; root->dirty_root = NULL; spin_lock(&root->list_lock); list_del_init(&dirty->root->dead_list); spin_unlock(&root->list_lock); kfree(dirty->root); kfree(dirty); /* make sure to update the root on disk * so we get any updates to the block used * counts */ err = btrfs_update_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); continue; } memset(&root->root_item.drop_progress, 0, sizeof(struct btrfs_disk_key)); root->root_item.drop_level = 0; root->commit_root = NULL; root->dirty_root = NULL; root->root_key.offset = root->fs_info->generation; btrfs_set_root_bytenr(&root->root_item, root->node->start); btrfs_set_root_level(&root->root_item, btrfs_header_level(root->node)); btrfs_set_root_generation(&root->root_item, root->root_key.offset); err = btrfs_insert_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); if (err) break; refs = btrfs_root_refs(&dirty->root->root_item); btrfs_set_root_refs(&dirty->root->root_item, refs - 1); err = btrfs_update_root(trans, root->fs_info->tree_root, &dirty->root->root_key, &dirty->root->root_item); BUG_ON(err); if (refs == 1) { list_add(&dirty->list, list); } else { WARN_ON(1); free_extent_buffer(dirty->root->node); kfree(dirty->root); kfree(dirty); } } } return err; }
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) { unsigned int i; u32 nr = btrfs_header_nritems(&l->header); struct btrfs_item *item; struct btrfs_extent_item *ei; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_csum_item *ci; struct btrfs_block_group_item *bi; u32 type; printf("leaf %llu ptrs %d free space %d generation %llu owner %llu\n", (u64)btrfs_header_blocknr(&l->header), nr, btrfs_leaf_free_space(root, l), (u64)btrfs_header_generation(&l->header), (u64)btrfs_header_owner(&l->header)); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = l->items + i; type = btrfs_disk_key_type(&item->key); printf("\titem %d key (%llu %x %llu) itemoff %d itemsize %d\n", i, (u64)btrfs_disk_key_objectid(&item->key), btrfs_disk_key_flags(&item->key), (u64)btrfs_disk_key_offset(&item->key), btrfs_item_offset(item), btrfs_item_size(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\n", (u64)btrfs_inode_generation(ii), (u64)btrfs_inode_size(ii), (u64)btrfs_inode_block_group(ii), btrfs_inode_mode(ii)); break; case BTRFS_DIR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l->items + i, di); break; case BTRFS_DIR_INDEX_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l->items + i, di); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); printf("\t\troot data blocknr %llu dirid %llu refs %u\n", (u64)btrfs_root_blocknr(ri), (u64)btrfs_root_dirid(ri), btrfs_root_refs(ri)); break; case BTRFS_EXTENT_ITEM_KEY: ei = btrfs_item_ptr(l, i, struct btrfs_extent_item); printf("\t\textent data refs %u owner %llu\n", btrfs_extent_refs(ei), (u64)btrfs_extent_owner(ei)); break; case BTRFS_CSUM_ITEM_KEY: ci = btrfs_item_ptr(l, i, struct btrfs_csum_item); printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE) { printf("\t\tinline extent data size %u\n", btrfs_file_extent_inline_len(l->items + i)); break; } printf("\t\textent data disk block %llu nr %llu\n", (u64)btrfs_file_extent_disk_blocknr(fi), (u64)btrfs_file_extent_disk_num_blocks(fi)); printf("\t\textent data offset %llu nr %llu\n", (u64)btrfs_file_extent_offset(fi), (u64)btrfs_file_extent_num_blocks(fi)); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); printf("\t\tblock group used %llu flags %x\n", (u64)btrfs_block_group_used(bi), bi->flags); break; case BTRFS_STRING_ITEM_KEY: printf("\t\titem data %.*s\n", btrfs_item_size(item), btrfs_leaf_data(l) + btrfs_item_offset(item)); break; }; fflush(stdout); } }
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); } }