int btrfs_test_qgroups(u32 sectorsize, u32 nodesize) { struct btrfs_fs_info *fs_info = NULL; struct btrfs_root *root; struct btrfs_root *tmp_root; int ret = 0; fs_info = btrfs_alloc_dummy_fs_info(); if (!fs_info) { test_msg("Couldn't allocate dummy fs info\n"); return -ENOMEM; } root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(root)) { test_msg("Couldn't allocate root\n"); ret = PTR_ERR(root); goto out; } /* We are using this root as our extent root */ root->fs_info->extent_root = root; /* * Some of the paths we test assume we have a filled out fs_info, so we * just need to add the root in there so we don't panic. */ root->fs_info->tree_root = root; root->fs_info->quota_root = root; set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); /* * Can't use bytenr 0, some things freak out * *cough*backref walking code*cough* */ root->node = alloc_test_extent_buffer(root->fs_info, nodesize, nodesize); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); ret = -ENOMEM; goto out; } btrfs_set_header_level(root->node, 0); btrfs_set_header_nritems(root->node, 0); root->alloc_bytenr += 2 * nodesize; tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(tmp_root)) { test_msg("Couldn't allocate a fs root\n"); ret = PTR_ERR(tmp_root); goto out; } tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID; root->fs_info->fs_root = tmp_root; ret = btrfs_insert_fs_root(root->fs_info, tmp_root); if (ret) { test_msg("Couldn't insert fs root %d\n", ret); goto out; } tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(tmp_root)) { test_msg("Couldn't allocate a fs root\n"); ret = PTR_ERR(tmp_root); goto out; } tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = btrfs_insert_fs_root(root->fs_info, tmp_root); if (ret) { test_msg("Couldn't insert fs root %d\n", ret); goto out; } test_msg("Running qgroup tests\n"); ret = test_no_shared_qgroup(root, sectorsize, nodesize); if (ret) goto out; ret = test_multiple_refs(root, sectorsize, nodesize); out: btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); return ret; }
int make_btrfs(int fd, const char *device, const char *label, u64 blocks[7], u64 num_bytes, u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, u64 features) { struct btrfs_super_block super; struct extent_buffer *buf; struct btrfs_root_item root_item; struct btrfs_disk_key disk_key; struct btrfs_extent_item *extent_item; struct btrfs_inode_item *inode_item; struct btrfs_chunk *chunk; struct btrfs_dev_item *dev_item; struct btrfs_dev_extent *dev_extent; u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; u8 *ptr; int i; int ret; u32 itemoff; u32 nritems = 0; u64 first_free; u64 ref_root; u32 array_size; u32 item_size; int skinny_metadata = !!(features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1; first_free &= ~((u64)sectorsize - 1); memset(&super, 0, sizeof(super)); num_bytes = (num_bytes / sectorsize) * sectorsize; uuid_generate(super.fsid); uuid_generate(super.dev_item.uuid); uuid_generate(chunk_tree_uuid); btrfs_set_super_bytenr(&super, blocks[0]); btrfs_set_super_num_devices(&super, 1); btrfs_set_super_magic(&super, BTRFS_MAGIC); btrfs_set_super_generation(&super, 1); btrfs_set_super_root(&super, blocks[1]); btrfs_set_super_chunk_root(&super, blocks[3]); btrfs_set_super_total_bytes(&super, num_bytes); btrfs_set_super_bytes_used(&super, 6 * leafsize); btrfs_set_super_sectorsize(&super, sectorsize); btrfs_set_super_leafsize(&super, leafsize); btrfs_set_super_nodesize(&super, nodesize); btrfs_set_super_stripesize(&super, stripesize); btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32); btrfs_set_super_chunk_root_generation(&super, 1); btrfs_set_super_cache_generation(&super, -1); btrfs_set_super_incompat_flags(&super, features); if (label) strncpy(super.label, label, BTRFS_LABEL_SIZE - 1); buf = malloc(sizeof(*buf) + max(sectorsize, leafsize)); /* create the tree of root objects */ memset(buf->data, 0, leafsize); buf->len = leafsize; btrfs_set_header_bytenr(buf, blocks[1]); btrfs_set_header_nritems(buf, 4); btrfs_set_header_generation(buf, 1); btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID); write_extent_buffer(buf, super.fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); write_extent_buffer(buf, chunk_tree_uuid, (unsigned long) btrfs_header_chunk_tree_uuid(buf), BTRFS_UUID_SIZE); /* create the items for the root tree */ memset(&root_item, 0, sizeof(root_item)); inode_item = &root_item.inode; btrfs_set_stack_inode_generation(inode_item, 1); btrfs_set_stack_inode_size(inode_item, 3); btrfs_set_stack_inode_nlink(inode_item, 1); btrfs_set_stack_inode_nbytes(inode_item, leafsize); btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); btrfs_set_root_refs(&root_item, 1); btrfs_set_root_used(&root_item, leafsize); btrfs_set_root_generation(&root_item, 1); memset(&disk_key, 0, sizeof(disk_key)); btrfs_set_disk_key_type(&disk_key, BTRFS_ROOT_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, 0); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[2]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[4]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[5]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[6]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_CSUM_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[1]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the items for the extent tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize); for (i = 1; i < 7; i++) { item_size = sizeof(struct btrfs_extent_item); if (!skinny_metadata) item_size += sizeof(struct btrfs_tree_block_info); BUG_ON(blocks[i] < first_free); BUG_ON(blocks[i] < blocks[i - 1]); /* create extent item */ itemoff -= item_size; btrfs_set_disk_key_objectid(&disk_key, blocks[i]); if (skinny_metadata) { btrfs_set_disk_key_type(&disk_key, BTRFS_METADATA_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, 0); } else { btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, leafsize); } btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); extent_item = btrfs_item_ptr(buf, nritems, struct btrfs_extent_item); btrfs_set_extent_refs(buf, extent_item, 1); btrfs_set_extent_generation(buf, extent_item, 1); btrfs_set_extent_flags(buf, extent_item, BTRFS_EXTENT_FLAG_TREE_BLOCK); nritems++; /* create extent ref */ ref_root = reference_root_table[i]; btrfs_set_disk_key_objectid(&disk_key, blocks[i]); btrfs_set_disk_key_offset(&disk_key, ref_root); btrfs_set_disk_key_type(&disk_key, BTRFS_TREE_BLOCK_REF_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), 0); nritems++; } btrfs_set_header_bytenr(buf, blocks[2]); btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[2]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the chunk tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; item_size = sizeof(*dev_item); itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - item_size; /* first device 1 (there is no device 0) */ btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID); btrfs_set_disk_key_offset(&disk_key, 1); btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_ITEM_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item); btrfs_set_device_id(buf, dev_item, 1); btrfs_set_device_generation(buf, dev_item, 0); btrfs_set_device_total_bytes(buf, dev_item, num_bytes); btrfs_set_device_bytes_used(buf, dev_item, BTRFS_MKFS_SYSTEM_GROUP_SIZE); btrfs_set_device_io_align(buf, dev_item, sectorsize); btrfs_set_device_io_width(buf, dev_item, sectorsize); btrfs_set_device_sector_size(buf, dev_item, sectorsize); btrfs_set_device_type(buf, dev_item, 0); write_extent_buffer(buf, super.dev_item.uuid, (unsigned long)btrfs_device_uuid(dev_item), BTRFS_UUID_SIZE); write_extent_buffer(buf, super.fsid, (unsigned long)btrfs_device_fsid(dev_item), BTRFS_UUID_SIZE); read_extent_buffer(buf, &super.dev_item, (unsigned long)dev_item, sizeof(*dev_item)); nritems++; item_size = btrfs_chunk_item_size(1); itemoff = itemoff - item_size; /* then we have chunk 0 */ btrfs_set_disk_key_objectid(&disk_key, BTRFS_FIRST_CHUNK_TREE_OBJECTID); btrfs_set_disk_key_offset(&disk_key, 0); btrfs_set_disk_key_type(&disk_key, BTRFS_CHUNK_ITEM_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); chunk = btrfs_item_ptr(buf, nritems, struct btrfs_chunk); btrfs_set_chunk_length(buf, chunk, BTRFS_MKFS_SYSTEM_GROUP_SIZE); btrfs_set_chunk_owner(buf, chunk, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_chunk_stripe_len(buf, chunk, 64 * 1024); btrfs_set_chunk_type(buf, chunk, BTRFS_BLOCK_GROUP_SYSTEM); btrfs_set_chunk_io_align(buf, chunk, sectorsize); btrfs_set_chunk_io_width(buf, chunk, sectorsize); btrfs_set_chunk_sector_size(buf, chunk, sectorsize); btrfs_set_chunk_num_stripes(buf, chunk, 1); btrfs_set_stripe_devid_nr(buf, chunk, 0, 1); btrfs_set_stripe_offset_nr(buf, chunk, 0, 0); nritems++; write_extent_buffer(buf, super.dev_item.uuid, (unsigned long)btrfs_stripe_dev_uuid(&chunk->stripe), BTRFS_UUID_SIZE); /* copy the key for the chunk to the system array */ ptr = super.sys_chunk_array; array_size = sizeof(disk_key); memcpy(ptr, &disk_key, sizeof(disk_key)); ptr += sizeof(disk_key); /* copy the chunk to the system array */ read_extent_buffer(buf, ptr, (unsigned long)chunk, item_size); array_size += item_size; ptr += item_size; btrfs_set_super_sys_array_size(&super, array_size); btrfs_set_header_bytenr(buf, blocks[3]); btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[3]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the device tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(struct btrfs_dev_extent); btrfs_set_disk_key_objectid(&disk_key, 1); btrfs_set_disk_key_offset(&disk_key, 0); btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_EXTENT_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(struct btrfs_dev_extent)); dev_extent = btrfs_item_ptr(buf, nritems, struct btrfs_dev_extent); btrfs_set_dev_extent_chunk_tree(buf, dev_extent, BTRFS_CHUNK_TREE_OBJECTID); btrfs_set_dev_extent_chunk_objectid(buf, dev_extent, BTRFS_FIRST_CHUNK_TREE_OBJECTID); btrfs_set_dev_extent_chunk_offset(buf, dev_extent, 0); write_extent_buffer(buf, chunk_tree_uuid, (unsigned long)btrfs_dev_extent_chunk_tree_uuid(dev_extent), BTRFS_UUID_SIZE); btrfs_set_dev_extent_length(buf, dev_extent, BTRFS_MKFS_SYSTEM_GROUP_SIZE); nritems++; btrfs_set_header_bytenr(buf, blocks[4]); btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[4]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the FS root */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); btrfs_set_header_bytenr(buf, blocks[5]); btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID); btrfs_set_header_nritems(buf, 0); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[5]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* finally create the csum root */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); btrfs_set_header_bytenr(buf, blocks[6]); btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID); btrfs_set_header_nritems(buf, 0); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[6]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* and write out the super block */ BUG_ON(sizeof(super) > sectorsize); memset(buf->data, 0, sectorsize); memcpy(buf->data, &super, sizeof(super)); buf->len = sectorsize; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, sectorsize, blocks[0]); if (ret != sectorsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } ret = 0; out: free(buf); return ret; }
static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize) { struct btrfs_fs_info *fs_info = NULL; struct inode *inode = NULL; struct btrfs_root *root = NULL; struct extent_map *em = NULL; u64 orig_start; u64 disk_bytenr; u64 offset; int ret = -ENOMEM; inode = btrfs_new_test_inode(); if (!inode) { test_msg("Couldn't allocate inode\n"); return ret; } BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; BTRFS_I(inode)->location.offset = 0; fs_info = btrfs_alloc_dummy_fs_info(); if (!fs_info) { test_msg("Couldn't allocate dummy fs info\n"); goto out; } root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(root)) { test_msg("Couldn't allocate root\n"); goto out; } root->node = alloc_dummy_extent_buffer(NULL, nodesize, nodesize); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); goto out; } /* * We will just free a dummy node if it's ref count is 2 so we need an * extra ref so our searches don't accidentally release our page. */ extent_buffer_get(root->node); btrfs_set_header_nritems(root->node, 0); btrfs_set_header_level(root->node, 0); ret = -EINVAL; /* First with no extents */ BTRFS_I(inode)->root = root; em = btrfs_get_extent(inode, NULL, 0, 0, sectorsize, 0); if (IS_ERR(em)) { em = NULL; test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { test_msg("Vacancy flag wasn't set properly\n"); goto out; } free_extent_map(em); btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); /* * All of the magic numbers are based on the mapping setup in * setup_file_extents, so if you change anything there you need to * update the comment and update the expected values below. */ setup_file_extents(root, sectorsize); em = btrfs_get_extent(inode, NULL, 0, 0, (u64)-1, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != 0 || em->len != 5) { test_msg("Unexpected extent wanted start 0 len 5, got start " "%llu len %llu\n", em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_INLINE) { test_msg("Expected an inline, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != (sectorsize - 5)) { test_msg("Unexpected extent wanted start %llu len 1, got start " "%llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } /* * We don't test anything else for inline since it doesn't get set * unless we have a page for it to write into. Maybe we should change * this? */ offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 4) { test_msg("Unexpected extent wanted start %llu len 4, got start " "%llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); /* Regular extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize - 1) { test_msg("Unexpected extent wanted start %llu len 4095, got " "start %llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* The next 3 are split extents */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start, em->orig_start); goto out; } disk_bytenr += (em->start - orig_start); if (em->block_start != disk_bytenr) { test_msg("Wrong block start, want %llu, have %llu\n", disk_bytenr, em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* Prealloc extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* The next 3 are a half written prealloc extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_HOLE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Unexpected orig offset, wanted %llu, have %llu\n", orig_start, em->orig_start); goto out; } if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { test_msg("Unexpected block start, wanted %llu, have %llu\n", disk_bytenr + (em->start - em->orig_start), em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start, em->orig_start); goto out; } if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { test_msg("Unexpected block start, wanted %llu, have %llu\n", disk_bytenr + (em->start - em->orig_start), em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* Now for the compressed extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } offset = em->start + em->len; free_extent_map(em); /* Split compressed extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != disk_bytenr) { test_msg("Block start does not match, want %llu got %llu\n", disk_bytenr, em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } offset = em->start + em->len; free_extent_map(em); /* A hole between regular extents but no hole extent */ em = btrfs_get_extent(inode, NULL, 0, offset + 6, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, 4096 * 1024, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole extent, got %llu\n", em->block_start); goto out; } /* * Currently we just return a length that we requested rather than the * length of the actual hole, if this changes we'll have to change this * test. */ if (em->start != offset || em->len != 3 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 3 * sectorsize, em->start, em->len); goto out; } if (em->flags != vacancy_only) { test_msg("Unexpected flags set, want %lu have %lu\n", vacancy_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } ret = 0; out: if (!IS_ERR(em)) free_extent_map(em); iput(inode); btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); return ret; }
static int test_hole_first(u32 sectorsize, u32 nodesize) { struct btrfs_fs_info *fs_info = NULL; struct inode *inode = NULL; struct btrfs_root *root = NULL; struct extent_map *em = NULL; int ret = -ENOMEM; inode = btrfs_new_test_inode(); if (!inode) { test_msg("Couldn't allocate inode\n"); return ret; } BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; BTRFS_I(inode)->location.offset = 0; fs_info = btrfs_alloc_dummy_fs_info(); if (!fs_info) { test_msg("Couldn't allocate dummy fs info\n"); goto out; } root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(root)) { test_msg("Couldn't allocate root\n"); goto out; } root->node = alloc_dummy_extent_buffer(NULL, nodesize, nodesize); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); goto out; } extent_buffer_get(root->node); btrfs_set_header_nritems(root->node, 0); btrfs_set_header_level(root->node, 0); BTRFS_I(inode)->root = root; ret = -EINVAL; /* * Need a blank inode item here just so we don't confuse * btrfs_get_extent. */ insert_inode_item_key(root); insert_extent(root, sectorsize, sectorsize, sectorsize, 0, sectorsize, sectorsize, BTRFS_FILE_EXTENT_REG, 0, 1); em = btrfs_get_extent(inode, NULL, 0, 0, 2 * sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != 0 || em->len != sectorsize) { test_msg("Unexpected extent wanted start 0 len %u, " "got start %llu len %llu\n", sectorsize, em->start, em->len); goto out; } if (em->flags != vacancy_only) { test_msg("Wrong flags, wanted %lu, have %lu\n", vacancy_only, em->flags); goto out; } free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, sectorsize, 2 * sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != sectorsize) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != sectorsize || em->len != sectorsize) { test_msg("Unexpected extent wanted start %u len %u, " "got start %llu len %llu\n", sectorsize, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, wanted 0 got %lu\n", em->flags); goto out; } ret = 0; out: if (!IS_ERR(em)) free_extent_map(em); iput(inode); btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); return ret; }
static int run_test(test_func_t test_func, int bitmaps) { struct btrfs_root *root = NULL; struct btrfs_block_group_cache *cache = NULL; struct btrfs_trans_handle trans; struct btrfs_path *path = NULL; int ret; root = btrfs_alloc_dummy_root(); if (IS_ERR(root)) { test_msg("Couldn't allocate dummy root\n"); ret = PTR_ERR(root); goto out; } root->fs_info = btrfs_alloc_dummy_fs_info(); if (!root->fs_info) { test_msg("Couldn't allocate dummy fs info\n"); ret = -ENOMEM; goto out; } btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); root->fs_info->free_space_root = root; root->fs_info->tree_root = root; root->node = alloc_test_extent_buffer(root->fs_info, 4096); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); ret = -ENOMEM; goto out; } btrfs_set_header_level(root->node, 0); btrfs_set_header_nritems(root->node, 0); root->alloc_bytenr += 8192; cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE); if (!cache) { test_msg("Couldn't allocate dummy block group cache\n"); ret = -ENOMEM; goto out; } cache->bitmap_low_thresh = 0; cache->bitmap_high_thresh = (u32)-1; cache->needs_free_space = 1; btrfs_init_dummy_trans(&trans); path = btrfs_alloc_path(); if (!path) { test_msg("Couldn't allocate path\n"); return -ENOMEM; } ret = add_block_group_free_space(&trans, root->fs_info, cache); if (ret) { test_msg("Could not add block group free space\n"); goto out; } if (bitmaps) { ret = convert_free_space_to_bitmaps(&trans, root->fs_info, cache, path); if (ret) { test_msg("Could not convert block group to bitmaps\n"); goto out; } } ret = test_func(&trans, root->fs_info, cache, path); if (ret) goto out; ret = remove_block_group_free_space(&trans, root->fs_info, cache); if (ret) { test_msg("Could not remove block group free space\n"); goto out; } if (btrfs_header_nritems(root->node) != 0) { test_msg("Free space tree has leftover items\n"); ret = -EINVAL; goto out; } ret = 0; out: btrfs_free_path(path); btrfs_free_dummy_block_group(cache); btrfs_free_dummy_root(root); return ret; }