btrfs: implement hole punching for RAID stripe extents

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>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Johannes Thumshirn 2025-01-13 20:31:48 +01:00 committed by David Sterba
parent 7664311904
commit 6aa0e7cc56
2 changed files with 49 additions and 0 deletions

View File

@ -3833,6 +3833,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)

View File

@ -140,6 +140,54 @@ 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,
};
/* The "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);
}
/* The "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);
break;
}
/*
* The stripe extent starts before the range we want to delete:
*