diff mbox series

[07/14] btrfs: implement hole punching for RAID stripe extents

Message ID 038e3971d12f2f8aef69a96c999916f37165f12b.1733989299.git.jth@kernel.org (mailing list archive)
State New
Headers show
Series btrfs: more RST delete fixes | expand

Commit Message

Johannes Thumshirn Dec. 12, 2024, 7:55 a.m. UTC
From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

If the stripe extent we want to delete starts before the range we want to
delete and ends after the range we want to delete we're punching a
hole in the stripe extent:

  |--- RAID Stripe Extent ---|
  | keep |--- drop ---| keep |

This means we need to a) truncate the existing item and b)
create a second item for the remaining range.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
 fs/btrfs/ctree.c            |  1 +
 fs/btrfs/raid-stripe-tree.c | 54 +++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

Comments

Filipe Manana Dec. 17, 2024, 4:05 p.m. UTC | #1
On Thu, Dec 12, 2024 at 7:56 AM Johannes Thumshirn <jth@kernel.org> wrote:
>
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>
> If the stripe extent we want to delete starts before the range we want to
> delete and ends after the range we want to delete we're punching a
> hole in the stripe extent:
>
>   |--- RAID Stripe Extent ---|
>   | keep |--- drop ---| keep |
>
> This means we need to a) truncate the existing item and b)
> create a second item for the remaining range.
>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> ---
>  fs/btrfs/ctree.c            |  1 +
>  fs/btrfs/raid-stripe-tree.c | 54 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
>
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 693dc27ffb89..5682692b5ba5 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -3903,6 +3903,7 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
>         btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
>
>         BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY &&
> +              key.type != BTRFS_RAID_STRIPE_KEY &&
>                key.type != BTRFS_EXTENT_CSUM_KEY);
>
>         if (btrfs_leaf_free_space(leaf) >= ins_len)
> diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
> index ccf455b30314..6ec72732c4ad 100644
> --- a/fs/btrfs/raid-stripe-tree.c
> +++ b/fs/btrfs/raid-stripe-tree.c
> @@ -138,6 +138,60 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
>                 trace_btrfs_raid_extent_delete(fs_info, start, end,
>                                                found_start, found_end);
>
> +               /*
> +                * The stripe extent starts before the range we want to delete
> +                * and ends after the range we want to delete, i.e. we're
> +                * punching a hole in the stripe extent:
> +                *
> +                *  |--- RAID Stripe Extent ---|
> +                *  | keep |--- drop ---| keep |
> +                *
> +                * This means we need to a) truncate the existing item and b)
> +                * create a second item for the remaining range.
> +                */
> +               if (found_start < start && found_end > end) {
> +                       size_t item_size;
> +                       u64 diff_start = start - found_start;
> +                       u64 diff_end = found_end - end;
> +                       struct btrfs_stripe_extent *extent;
> +                       struct btrfs_key newkey = {
> +                               .objectid = end,
> +                               .type = BTRFS_RAID_STRIPE_KEY,
> +                               .offset = diff_end,
> +                       };
> +
> +                       /* "right" item */
> +                       ret = btrfs_duplicate_item(trans, stripe_root, path,
> +                                                  &newkey);
> +                       if (ret)
> +                               break;
> +
> +                       item_size = btrfs_item_size(leaf, path->slots[0]);
> +                       extent = btrfs_item_ptr(leaf, path->slots[0],
> +                                               struct btrfs_stripe_extent);
> +
> +                       for (int i = 0; i < btrfs_num_raid_stripes(item_size);
> +                            i++) {

We can place this in a single line, nowadays we tolerate more than 80
characters, anything up to 90 is fine.
It makes things more readable.

> +                               struct btrfs_raid_stride *stride =
> +                                       &extent->strides[i];

Same here.

> +                               u64 phys;
> +
> +                               phys = btrfs_raid_stride_physical(leaf, stride);
> +                               phys += diff_start + length;
> +                               btrfs_set_raid_stride_physical(leaf, stride,
> +                                                              phys);

Same here.
> +                       }
> +                       btrfs_mark_buffer_dirty(trans, leaf);

Not needed, already done down the call chain of btrfs_duplicate_item().

> +
> +                       /* "left" item */
> +                       path->slots[0]--;
> +                       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
> +                       btrfs_partially_delete_raid_extent(trans, path, &key,
> +                                                          diff_start, 0);
> +                       length = 0;
> +                       break;

There's the 'break', no need to assign 0 to the length as it's not
used anymore after breaking out of the loop.

Otherwise it looks good, thanks.

> +               }
> +
>                 /*
>                  * The stripe extent starts before the range we want to delete:
>                  *
> --
> 2.43.0
>
>
diff mbox series

Patch

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 693dc27ffb89..5682692b5ba5 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3903,6 +3903,7 @@  static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
 	btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 
 	BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY &&
+	       key.type != BTRFS_RAID_STRIPE_KEY &&
 	       key.type != BTRFS_EXTENT_CSUM_KEY);
 
 	if (btrfs_leaf_free_space(leaf) >= ins_len)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index ccf455b30314..6ec72732c4ad 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -138,6 +138,60 @@  int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
 		trace_btrfs_raid_extent_delete(fs_info, start, end,
 					       found_start, found_end);
 
+		/*
+		 * The stripe extent starts before the range we want to delete
+		 * and ends after the range we want to delete, i.e. we're
+		 * punching a hole in the stripe extent:
+		 *
+		 *  |--- RAID Stripe Extent ---|
+		 *  | keep |--- drop ---| keep |
+		 *
+		 * This means we need to a) truncate the existing item and b)
+		 * create a second item for the remaining range.
+		 */
+		if (found_start < start && found_end > end) {
+			size_t item_size;
+			u64 diff_start = start - found_start;
+			u64 diff_end = found_end - end;
+			struct btrfs_stripe_extent *extent;
+			struct btrfs_key newkey = {
+				.objectid = end,
+				.type = BTRFS_RAID_STRIPE_KEY,
+				.offset = diff_end,
+			};
+
+			/* "right" item */
+			ret = btrfs_duplicate_item(trans, stripe_root, path,
+						   &newkey);
+			if (ret)
+				break;
+
+			item_size = btrfs_item_size(leaf, path->slots[0]);
+			extent = btrfs_item_ptr(leaf, path->slots[0],
+						struct btrfs_stripe_extent);
+
+			for (int i = 0; i < btrfs_num_raid_stripes(item_size);
+			     i++) {
+				struct btrfs_raid_stride *stride =
+					&extent->strides[i];
+				u64 phys;
+
+				phys = btrfs_raid_stride_physical(leaf, stride);
+				phys += diff_start + length;
+				btrfs_set_raid_stride_physical(leaf, stride,
+							       phys);
+			}
+			btrfs_mark_buffer_dirty(trans, leaf);
+
+			/* "left" item */
+			path->slots[0]--;
+			btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+			btrfs_partially_delete_raid_extent(trans, path, &key,
+							   diff_start, 0);
+			length = 0;
+			break;
+		}
+
 		/*
 		 * The stripe extent starts before the range we want to delete:
 		 *