Commit 92e1229b authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba
Browse files

btrfs: tests: test invalid splitting when skipping pinned drop extent_map



This reproduces the bug fixed by "btrfs: fix incorrect splitting in
btrfs_drop_extent_map_range", we were improperly calculating the range
for the split extent.  Add a test that exercises this scenario and
validates that we get the correct resulting extent_maps in our tree.

Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent f345dbdf
Loading
Loading
Loading
Loading
+138 −0
Original line number Diff line number Diff line
@@ -708,6 +708,141 @@ static int test_case_6(struct btrfs_fs_info *fs_info, struct extent_map_tree *em
	return ret;
}

/*
 * Regression test for btrfs_drop_extent_map_range.  Calling with skip_pinned ==
 * true would mess up the start/end calculations and subsequent splits would be
 * incorrect.
 */
static int test_case_7(void)
{
	struct extent_map_tree *em_tree;
	struct extent_map *em;
	struct inode *inode;
	int ret;

	test_msg("Running btrfs_drop_extent_cache with pinned");

	inode = btrfs_new_test_inode();
	if (!inode) {
		test_std_err(TEST_ALLOC_INODE);
		return -ENOMEM;
	}

	em_tree = &BTRFS_I(inode)->extent_tree;

	em = alloc_extent_map();
	if (!em) {
		test_std_err(TEST_ALLOC_EXTENT_MAP);
		ret = -ENOMEM;
		goto out;
	}

	/* [0, 16K), pinned */
	em->start = 0;
	em->len = SZ_16K;
	em->block_start = 0;
	em->block_len = SZ_4K;
	set_bit(EXTENT_FLAG_PINNED, &em->flags);
	write_lock(&em_tree->lock);
	ret = add_extent_mapping(em_tree, em, 0);
	write_unlock(&em_tree->lock);
	if (ret < 0) {
		test_err("couldn't add extent map");
		goto out;
	}
	free_extent_map(em);

	em = alloc_extent_map();
	if (!em) {
		test_std_err(TEST_ALLOC_EXTENT_MAP);
		ret = -ENOMEM;
		goto out;
	}

	/* [32K, 48K), not pinned */
	em->start = SZ_32K;
	em->len = SZ_16K;
	em->block_start = SZ_32K;
	em->block_len = SZ_16K;
	write_lock(&em_tree->lock);
	ret = add_extent_mapping(em_tree, em, 0);
	write_unlock(&em_tree->lock);
	if (ret < 0) {
		test_err("couldn't add extent map");
		goto out;
	}
	free_extent_map(em);

	/*
	 * Drop [0, 36K) This should skip the [0, 4K) extent and then split the
	 * [32K, 48K) extent.
	 */
	btrfs_drop_extent_map_range(BTRFS_I(inode), 0, (36 * SZ_1K) - 1, true);

	/* Make sure our extent maps look sane. */
	ret = -EINVAL;

	em = lookup_extent_mapping(em_tree, 0, SZ_16K);
	if (!em) {
		test_err("didn't find an em at 0 as expected");
		goto out;
	}

	if (em->start != 0) {
		test_err("em->start is %llu, expected 0", em->start);
		goto out;
	}

	if (em->len != SZ_16K) {
		test_err("em->len is %llu, expected 16K", em->len);
		goto out;
	}

	free_extent_map(em);

	read_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, SZ_16K, SZ_16K);
	read_unlock(&em_tree->lock);
	if (em) {
		test_err("found an em when we weren't expecting one");
		goto out;
	}

	read_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, SZ_32K, SZ_16K);
	read_unlock(&em_tree->lock);
	if (!em) {
		test_err("didn't find an em at 32K as expected");
		goto out;
	}

	if (em->start != (36 * SZ_1K)) {
		test_err("em->start is %llu, expected 36K", em->start);
		goto out;
	}

	if (em->len != (12 * SZ_1K)) {
		test_err("em->len is %llu, expected 12K", em->len);
		goto out;
	}

	free_extent_map(em);

	read_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, 48 * SZ_1K, (u64)-1);
	read_unlock(&em_tree->lock);
	if (em) {
		test_err("found an unexpected em above 48K");
		goto out;
	}

	ret = 0;
out:
	free_extent_map(em);
	iput(inode);
	return ret;
}

struct rmap_test_vector {
	u64 raid_type;
	u64 physical_start;
@@ -891,6 +1026,9 @@ int btrfs_test_extent_map(void)
	if (ret)
		goto out;
	ret = test_case_6(fs_info, em_tree);
	if (ret)
		goto out;
	ret = test_case_7();
	if (ret)
		goto out;