1

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: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Josef Bacik 2023-08-17 16:57:33 -04:00 committed by David Sterba
parent f345dbdf2c
commit 92e1229b20

View File

@ -708,6 +708,141 @@ out:
return ret; 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 { struct rmap_test_vector {
u64 raid_type; u64 raid_type;
u64 physical_start; u64 physical_start;
@ -891,6 +1026,9 @@ int btrfs_test_extent_map(void)
if (ret) if (ret)
goto out; goto out;
ret = test_case_6(fs_info, em_tree); ret = test_case_6(fs_info, em_tree);
if (ret)
goto out;
ret = test_case_7();
if (ret) if (ret)
goto out; goto out;