Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}