Commit bf2e2eb0 authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba
Browse files

btrfs: Add self-tests for btrfs_rmap_block



Add RAID1 and single testcases to verify that data stripes are excluded
from super block locations and that the address mapping is valid.

Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
[ update changelog ]
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent b3ad2c17
Loading
Loading
Loading
Loading
+153 −1
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@
#include <linux/types.h>
#include "btrfs-tests.h"
#include "../ctree.h"
#include "../volumes.h"
#include "../disk-io.h"
#include "../block-group.h"

static void free_extent_map_tree(struct extent_map_tree *em_tree)
{
@@ -437,11 +440,153 @@ static int test_case_4(struct btrfs_fs_info *fs_info,
	return ret;
}

struct rmap_test_vector {
	u64 raid_type;
	u64 physical_start;
	u64 data_stripe_size;
	u64 num_data_stripes;
	u64 num_stripes;
	/* Assume we won't have more than 5 physical stripes */
	u64 data_stripe_phys_start[5];
	bool expected_mapped_addr;
	/* Physical to logical addresses */
	u64 mapped_logical[5];
};

static int test_rmap_block(struct btrfs_fs_info *fs_info,
			   struct rmap_test_vector *test)
{
	struct extent_map *em;
	struct map_lookup *map = NULL;
	u64 *logical = NULL;
	int i, out_ndaddrs, out_stripe_len;
	int ret;

	em = alloc_extent_map();
	if (!em) {
		test_std_err(TEST_ALLOC_EXTENT_MAP);
		return -ENOMEM;
	}

	map = kmalloc(map_lookup_size(test->num_stripes), GFP_KERNEL);
	if (!map) {
		kfree(em);
		test_std_err(TEST_ALLOC_EXTENT_MAP);
		return -ENOMEM;
	}

	set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
	/* Start at 4GiB logical address */
	em->start = SZ_4G;
	em->len = test->data_stripe_size * test->num_data_stripes;
	em->block_len = em->len;
	em->orig_block_len = test->data_stripe_size;
	em->map_lookup = map;

	map->num_stripes = test->num_stripes;
	map->stripe_len = BTRFS_STRIPE_LEN;
	map->type = test->raid_type;

	for (i = 0; i < map->num_stripes; i++) {
		struct btrfs_device *dev = btrfs_alloc_dummy_device(fs_info);

		if (IS_ERR(dev)) {
			test_err("cannot allocate device");
			ret = PTR_ERR(dev);
			goto out;
		}
		map->stripes[i].dev = dev;
		map->stripes[i].physical = test->data_stripe_phys_start[i];
	}

	write_lock(&fs_info->mapping_tree.lock);
	ret = add_extent_mapping(&fs_info->mapping_tree, em, 0);
	write_unlock(&fs_info->mapping_tree.lock);
	if (ret) {
		test_err("error adding block group mapping to mapping tree");
		goto out_free;
	}

	ret = btrfs_rmap_block(fs_info, em->start, btrfs_sb_offset(1),
			       &logical, &out_ndaddrs, &out_stripe_len);
	if (ret || (out_ndaddrs == 0 && test->expected_mapped_addr)) {
		test_err("didn't rmap anything but expected %d",
			 test->expected_mapped_addr);
		goto out;
	}

	if (out_stripe_len != BTRFS_STRIPE_LEN) {
		test_err("calculated stripe length doesn't match");
		goto out;
	}

	if (out_ndaddrs != test->expected_mapped_addr) {
		for (i = 0; i < out_ndaddrs; i++)
			test_msg("mapped %llu", logical[i]);
		test_err("unexpected number of mapped addresses: %d", out_ndaddrs);
		goto out;
	}

	for (i = 0; i < out_ndaddrs; i++) {
		if (logical[i] != test->mapped_logical[i]) {
			test_err("unexpected logical address mapped");
			goto out;
		}
	}

	ret = 0;
out:
	write_lock(&fs_info->mapping_tree.lock);
	remove_extent_mapping(&fs_info->mapping_tree, em);
	write_unlock(&fs_info->mapping_tree.lock);
	/* For us */
	free_extent_map(em);
out_free:
	/* For the tree */
	free_extent_map(em);
	kfree(logical);
	return ret;
}

int btrfs_test_extent_map(void)
{
	struct btrfs_fs_info *fs_info = NULL;
	struct extent_map_tree *em_tree;
	int ret = 0;
	int ret = 0, i;
	struct rmap_test_vector rmap_tests[] = {
		{
			/*
			 * Test a chunk with 2 data stripes one of which
			 * interesects the physical address of the super block
			 * is correctly recognised.
			 */
			.raid_type = BTRFS_BLOCK_GROUP_RAID1,
			.physical_start = SZ_64M - SZ_4M,
			.data_stripe_size = SZ_256M,
			.num_data_stripes = 2,
			.num_stripes = 2,
			.data_stripe_phys_start =
				{SZ_64M - SZ_4M, SZ_64M - SZ_4M + SZ_256M},
			.expected_mapped_addr = true,
			.mapped_logical= {SZ_4G + SZ_4M}
		},
		{
			/*
			 * Test that out-of-range physical addresses are
			 * ignored
			 */

			 /* SINGLE chunk type */
			.raid_type = 0,
			.physical_start = SZ_4G,
			.data_stripe_size = SZ_256M,
			.num_data_stripes = 1,
			.num_stripes = 1,
			.data_stripe_phys_start = {SZ_256M},
			.expected_mapped_addr = false,
			.mapped_logical = {0}
		}
	};

	test_msg("running extent_map tests");

@@ -474,6 +619,13 @@ int btrfs_test_extent_map(void)
		goto out;
	ret = test_case_4(fs_info, em_tree);

	test_msg("running rmap tests");
	for (i = 0; i < ARRAY_SIZE(rmap_tests); i++) {
		ret = test_rmap_block(fs_info, &rmap_tests[i]);
		if (ret)
			goto out;
	}

out:
	kfree(em_tree);
	btrfs_free_dummy_fs_info(fs_info);