diff mbox series

[v5,2/2] btrfs: implement self-tests for partial RAID srtipe-tree delete

Message ID 20241023132518.19830-3-jth@kernel.org (mailing list archive)
State New
Headers show
Series implement truncation for RAID stripe-extents | expand

Commit Message

Johannes Thumshirn Oct. 23, 2024, 1:25 p.m. UTC
From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

Implement self-tests for partial deletion of RAID stripe-tree entries.

These two new tests cover both the deletion of the front of a RAID
stripe-tree stripe extent as well as truncation of an item to make it
smaller.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/tests/raid-stripe-tree-tests.c | 224 ++++++++++++++++++++++++
 1 file changed, 224 insertions(+)

Comments

Filipe Manana Oct. 23, 2024, 5:45 p.m. UTC | #1
On Wed, Oct 23, 2024 at 2:25 PM Johannes Thumshirn <jth@kernel.org> wrote:
>
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>
> Implement self-tests for partial deletion of RAID stripe-tree entries.
>
> These two new tests cover both the deletion of the front of a RAID
> stripe-tree stripe extent as well as truncation of an item to make it
> smaller.
>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> Reviewed-by: Filipe Manana <fdmanana@suse.com>
> ---
>  fs/btrfs/tests/raid-stripe-tree-tests.c | 224 ++++++++++++++++++++++++
>  1 file changed, 224 insertions(+)
>
> diff --git a/fs/btrfs/tests/raid-stripe-tree-tests.c b/fs/btrfs/tests/raid-stripe-tree-tests.c
> index b8013ab13c43..3e6932de5623 100644
> --- a/fs/btrfs/tests/raid-stripe-tree-tests.c
> +++ b/fs/btrfs/tests/raid-stripe-tree-tests.c
> @@ -29,6 +29,228 @@ static struct btrfs_device *btrfs_device_by_devid(struct btrfs_fs_devices *fs_de
>         return NULL;
>  }
>
> +/*
> + * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
> + * delete the 1st 32K, making the new start address 1M+32K.
> + */
> +static int test_front_delete(struct btrfs_trans_handle *trans)
> +{
> +       struct btrfs_fs_info *fs_info = trans->fs_info;
> +       struct btrfs_io_context *bioc;
> +       struct btrfs_io_stripe io_stripe = { 0 };
> +       u64 map_type = RST_TEST_RAID1_TYPE;
> +       u64 logical = SZ_1M;
> +       u64 len = SZ_64K;
> +       int ret;
> +
> +       bioc = alloc_btrfs_io_context(fs_info, logical, RST_TEST_NUM_DEVICES);
> +       if (!bioc) {
> +               test_std_err(TEST_ALLOC_IO_CONTEXT);
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
> +       bioc->map_type = map_type;
> +       bioc->size = len;
> +
> +       for (int i = 0; i < RST_TEST_NUM_DEVICES; i++) {
> +               struct btrfs_io_stripe *stripe = &bioc->stripes[i];
> +
> +               stripe->dev = btrfs_device_by_devid(fs_info->fs_devices, i);
> +               if (!stripe->dev) {
> +                       test_err("cannot find device with devid %d", i);
> +                       ret = -EINVAL;
> +                       goto out;
> +               }
> +
> +               stripe->physical = logical + i * SZ_1G;
> +       }
> +
> +       ret = btrfs_insert_one_raid_extent(trans, bioc);
> +       if (ret) {
> +               test_err("inserting RAID extent failed: %d", ret);
> +               goto out;
> +       }
> +
> +       ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
> +                                          &io_stripe);
> +       if (ret) {
> +               test_err("lookup of RAID extent [%llu, %llu] failed", logical,
> +                        logical + len);
> +               goto out;
> +       }
> +
> +       if (io_stripe.physical != logical) {
> +               test_err("invalid physical address, expected %llu got %llu",
> +                        logical, io_stripe.physical);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (len != SZ_64K) {
> +               test_err("invalid stripe length, expected %llu got %llu",
> +                        (u64)SZ_64K, len);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = btrfs_delete_raid_extent(trans, logical, SZ_32K);
> +       if (ret) {
> +               test_err("deleting RAID extent [%llu, %llu] failed", logical,
> +                        logical + SZ_32K);
> +               goto out;
> +       }
> +
> +       len = SZ_32K;
> +       ret = btrfs_get_raid_extent_offset(fs_info, logical + SZ_32K, &len,
> +                                          map_type, 0, &io_stripe);
> +       if (ret) {
> +               test_err("lookup of RAID extent [%llu, %llu] failed",
> +                        logical + SZ_32K, logical + SZ_32K + len);
> +               goto out;
> +       }
> +
> +       if (io_stripe.physical != logical + SZ_32K) {
> +               test_err("invalid physical address, expected %llu, got %llu",
> +                        logical + SZ_32K, io_stripe.physical);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (len != SZ_32K) {
> +               test_err("invalid stripe length, expected %llu, got %llu",
> +                        (u64)SZ_32K, len);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
> +                                          &io_stripe);
> +       if (!ret) {
> +               ret = -EINVAL;
> +               test_err("lookup of RAID extent [%llu, %llu] succeeded, should fail",
> +                        logical, logical + SZ_32K);
> +               goto out;
> +       }
> +
> +       ret = btrfs_delete_raid_extent(trans, logical + SZ_32K, SZ_32K);
> +       btrfs_put_bioc(bioc);
> + out:

The btrfs_put_bioc(bioc) call needs to be put under the 'out' label,
otherwise we will leak it in case an error happens.
It is correct in the next test function, but not in this one.

Thanks.

> +       return ret;
> +}
> +
> +/*
> + * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
> + * truncate the stripe extent down to 32K.
> + */
> +static int test_tail_delete(struct btrfs_trans_handle *trans)
> +{
> +       struct btrfs_fs_info *fs_info = trans->fs_info;
> +       struct btrfs_io_context *bioc;
> +       struct btrfs_io_stripe io_stripe = { 0 };
> +       u64 map_type = RST_TEST_RAID1_TYPE;
> +       u64 logical = SZ_1M;
> +       u64 len = SZ_64K;
> +       int ret;
> +
> +       bioc = alloc_btrfs_io_context(fs_info, logical, RST_TEST_NUM_DEVICES);
> +       if (!bioc) {
> +               test_std_err(TEST_ALLOC_IO_CONTEXT);
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
> +       bioc->map_type = map_type;
> +       bioc->size = len;
> +
> +       for (int i = 0; i < RST_TEST_NUM_DEVICES; i++) {
> +               struct btrfs_io_stripe *stripe = &bioc->stripes[i];
> +
> +               stripe->dev = btrfs_device_by_devid(fs_info->fs_devices, i);
> +               if (!stripe->dev) {
> +                       test_err("cannot find device with devid %d", i);
> +                       ret = -EINVAL;
> +                       goto out;
> +               }
> +
> +               stripe->physical = logical + i * SZ_1G;
> +       }
> +
> +       ret = btrfs_insert_one_raid_extent(trans, bioc);
> +       if (ret) {
> +               test_err("inserting RAID extent failed: %d", ret);
> +               goto out;
> +       }
> +
> +       io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
> +       if (!io_stripe.dev) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
> +                                          &io_stripe);
> +       if (ret) {
> +               test_err("lookup of RAID extent [%llu, %llu] failed", logical,
> +                        logical + len);
> +               goto out;
> +       }
> +
> +       if (io_stripe.physical != logical) {
> +               test_err("invalid physical address, expected %llu got %llu",
> +                        logical, io_stripe.physical);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (len != SZ_64K) {
> +               test_err("invalid stripe length, expected %llu got %llu",
> +                        (u64)SZ_64K, len);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = btrfs_delete_raid_extent(trans, logical + SZ_32K, SZ_32K);
> +       if (ret) {
> +               test_err("deleting RAID extent [%llu, %llu] failed",
> +                        logical + SZ_32K, logical + SZ_64K);
> +               goto out;
> +       }
> +
> +       len = SZ_32K;
> +       ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0, &io_stripe);
> +       if (ret) {
> +               test_err("lookup of RAID extent [%llu, %llu] failed", logical,
> +                        logical + len);
> +               goto out;
> +       }
> +
> +       if (io_stripe.physical != logical) {
> +               test_err("invalid physical address, expected %llu, got %llu",
> +                        logical, io_stripe.physical);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (len != SZ_32K) {
> +               test_err("invalid stripe length, expected %llu, got %llu",
> +                        (u64)SZ_32K, len);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = btrfs_delete_raid_extent(trans, logical, len);
> +       if (ret)
> +               test_err("deleting RAID extent [%llu, %llu] failed", logical,
> +                        logical + len);
> +
> +out:
> +       btrfs_put_bioc(bioc);
> +       return ret;
> +}
> +
>  /*
>   * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
>   * overwrite the whole range giving it new physical address at an offset of 1G.
> @@ -235,6 +457,8 @@ static int test_simple_create_delete(struct btrfs_trans_handle *trans)
>  static const test_func_t tests[] = {
>         test_simple_create_delete,
>         test_create_update_delete,
> +       test_tail_delete,
> +       test_front_delete,
>  };
>
>  static int run_test(test_func_t test, u32 sectorsize, u32 nodesize)
> --
> 2.43.0
>
>
David Sterba Oct. 23, 2024, 6:53 p.m. UTC | #2
On Wed, Oct 23, 2024 at 06:45:49PM +0100, Filipe Manana wrote:
> On Wed, Oct 23, 2024 at 2:25 PM Johannes Thumshirn <jth@kernel.org> wrote:
> > +                                          &io_stripe);
> > +       if (!ret) {
> > +               ret = -EINVAL;
> > +               test_err("lookup of RAID extent [%llu, %llu] succeeded, should fail",
> > +                        logical, logical + SZ_32K);
> > +               goto out;
> > +       }
> > +
> > +       ret = btrfs_delete_raid_extent(trans, logical + SZ_32K, SZ_32K);
> > +       btrfs_put_bioc(bioc);
> > + out:
> 
> The btrfs_put_bioc(bioc) call needs to be put under the 'out' label,
> otherwise we will leak it in case an error happens.
> It is correct in the next test function, but not in this one.

Fixed in for-next, thanks.
diff mbox series

Patch

diff --git a/fs/btrfs/tests/raid-stripe-tree-tests.c b/fs/btrfs/tests/raid-stripe-tree-tests.c
index b8013ab13c43..3e6932de5623 100644
--- a/fs/btrfs/tests/raid-stripe-tree-tests.c
+++ b/fs/btrfs/tests/raid-stripe-tree-tests.c
@@ -29,6 +29,228 @@  static struct btrfs_device *btrfs_device_by_devid(struct btrfs_fs_devices *fs_de
 	return NULL;
 }
 
+/*
+ * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
+ * delete the 1st 32K, making the new start address 1M+32K.
+ */
+static int test_front_delete(struct btrfs_trans_handle *trans)
+{
+	struct btrfs_fs_info *fs_info = trans->fs_info;
+	struct btrfs_io_context *bioc;
+	struct btrfs_io_stripe io_stripe = { 0 };
+	u64 map_type = RST_TEST_RAID1_TYPE;
+	u64 logical = SZ_1M;
+	u64 len = SZ_64K;
+	int ret;
+
+	bioc = alloc_btrfs_io_context(fs_info, logical, RST_TEST_NUM_DEVICES);
+	if (!bioc) {
+		test_std_err(TEST_ALLOC_IO_CONTEXT);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
+	bioc->map_type = map_type;
+	bioc->size = len;
+
+	for (int i = 0; i < RST_TEST_NUM_DEVICES; i++) {
+		struct btrfs_io_stripe *stripe = &bioc->stripes[i];
+
+		stripe->dev = btrfs_device_by_devid(fs_info->fs_devices, i);
+		if (!stripe->dev) {
+			test_err("cannot find device with devid %d", i);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		stripe->physical = logical + i * SZ_1G;
+	}
+
+	ret = btrfs_insert_one_raid_extent(trans, bioc);
+	if (ret) {
+		test_err("inserting RAID extent failed: %d", ret);
+		goto out;
+	}
+
+	ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
+					   &io_stripe);
+	if (ret) {
+		test_err("lookup of RAID extent [%llu, %llu] failed", logical,
+			 logical + len);
+		goto out;
+	}
+
+	if (io_stripe.physical != logical) {
+		test_err("invalid physical address, expected %llu got %llu",
+			 logical, io_stripe.physical);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len != SZ_64K) {
+		test_err("invalid stripe length, expected %llu got %llu",
+			 (u64)SZ_64K, len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_delete_raid_extent(trans, logical, SZ_32K);
+	if (ret) {
+		test_err("deleting RAID extent [%llu, %llu] failed", logical,
+			 logical + SZ_32K);
+		goto out;
+	}
+
+	len = SZ_32K;
+	ret = btrfs_get_raid_extent_offset(fs_info, logical + SZ_32K, &len,
+					   map_type, 0, &io_stripe);
+	if (ret) {
+		test_err("lookup of RAID extent [%llu, %llu] failed",
+			 logical + SZ_32K, logical + SZ_32K + len);
+		goto out;
+	}
+
+	if (io_stripe.physical != logical + SZ_32K) {
+		test_err("invalid physical address, expected %llu, got %llu",
+			 logical + SZ_32K, io_stripe.physical);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len != SZ_32K) {
+		test_err("invalid stripe length, expected %llu, got %llu",
+			 (u64)SZ_32K, len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
+					   &io_stripe);
+	if (!ret) {
+		ret = -EINVAL;
+		test_err("lookup of RAID extent [%llu, %llu] succeeded, should fail",
+			 logical, logical + SZ_32K);
+		goto out;
+	}
+
+	ret = btrfs_delete_raid_extent(trans, logical + SZ_32K, SZ_32K);
+	btrfs_put_bioc(bioc);
+ out:
+	return ret;
+}
+
+/*
+ * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
+ * truncate the stripe extent down to 32K.
+ */
+static int test_tail_delete(struct btrfs_trans_handle *trans)
+{
+	struct btrfs_fs_info *fs_info = trans->fs_info;
+	struct btrfs_io_context *bioc;
+	struct btrfs_io_stripe io_stripe = { 0 };
+	u64 map_type = RST_TEST_RAID1_TYPE;
+	u64 logical = SZ_1M;
+	u64 len = SZ_64K;
+	int ret;
+
+	bioc = alloc_btrfs_io_context(fs_info, logical, RST_TEST_NUM_DEVICES);
+	if (!bioc) {
+		test_std_err(TEST_ALLOC_IO_CONTEXT);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
+	bioc->map_type = map_type;
+	bioc->size = len;
+
+	for (int i = 0; i < RST_TEST_NUM_DEVICES; i++) {
+		struct btrfs_io_stripe *stripe = &bioc->stripes[i];
+
+		stripe->dev = btrfs_device_by_devid(fs_info->fs_devices, i);
+		if (!stripe->dev) {
+			test_err("cannot find device with devid %d", i);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		stripe->physical = logical + i * SZ_1G;
+	}
+
+	ret = btrfs_insert_one_raid_extent(trans, bioc);
+	if (ret) {
+		test_err("inserting RAID extent failed: %d", ret);
+		goto out;
+	}
+
+	io_stripe.dev = btrfs_device_by_devid(fs_info->fs_devices, 0);
+	if (!io_stripe.dev) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0,
+					   &io_stripe);
+	if (ret) {
+		test_err("lookup of RAID extent [%llu, %llu] failed", logical,
+			 logical + len);
+		goto out;
+	}
+
+	if (io_stripe.physical != logical) {
+		test_err("invalid physical address, expected %llu got %llu",
+			 logical, io_stripe.physical);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len != SZ_64K) {
+		test_err("invalid stripe length, expected %llu got %llu",
+			 (u64)SZ_64K, len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_delete_raid_extent(trans, logical + SZ_32K, SZ_32K);
+	if (ret) {
+		test_err("deleting RAID extent [%llu, %llu] failed",
+			 logical + SZ_32K, logical + SZ_64K);
+		goto out;
+	}
+
+	len = SZ_32K;
+	ret = btrfs_get_raid_extent_offset(fs_info, logical, &len, map_type, 0, &io_stripe);
+	if (ret) {
+		test_err("lookup of RAID extent [%llu, %llu] failed", logical,
+			 logical + len);
+		goto out;
+	}
+
+	if (io_stripe.physical != logical) {
+		test_err("invalid physical address, expected %llu, got %llu",
+			 logical, io_stripe.physical);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len != SZ_32K) {
+		test_err("invalid stripe length, expected %llu, got %llu",
+			 (u64)SZ_32K, len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_delete_raid_extent(trans, logical, len);
+	if (ret)
+		test_err("deleting RAID extent [%llu, %llu] failed", logical,
+			 logical + len);
+
+out:
+	btrfs_put_bioc(bioc);
+	return ret;
+}
+
 /*
  * Test a 64K RST write on a 2 disk RAID1 at a logical address of 1M and then
  * overwrite the whole range giving it new physical address at an offset of 1G.
@@ -235,6 +457,8 @@  static int test_simple_create_delete(struct btrfs_trans_handle *trans)
 static const test_func_t tests[] = {
 	test_simple_create_delete,
 	test_create_update_delete,
+	test_tail_delete,
+	test_front_delete,
 };
 
 static int run_test(test_func_t test, u32 sectorsize, u32 nodesize)