]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: implement hole punching for RAID stripe extents
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Mon, 13 Jan 2025 19:31:48 +0000 (20:31 +0100)
committerDavid Sterba <dsterba@suse.com>
Tue, 14 Jan 2025 14:52:13 +0000 (15:52 +0100)
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>
fs/btrfs/ctree.c
fs/btrfs/raid-stripe-tree.c

index c93f52a30a16028470594de1d1256dbec5c7899c..92071ca0655f0f1920eb841e77d3444a0e0d8834 100644 (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)
index bf665fdef18b016feca1f784b838a67cdc55e751..858abf518e9b4f16aa881e683ca893c3218412dd 100644 (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:
                 *