Skip to content

Commit

Permalink
btrfs: implement hole punching for RAID stripe extents
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Thumshirn authored and David Sterba committed Jan 14, 2025
1 parent 7664311 commit 6aa0e7c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
48 changes: 48 additions & 0 deletions fs/btrfs/raid-stripe-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
*
Expand Down

0 comments on commit 6aa0e7c

Please sign in to comment.