Skip to content

Commit

Permalink
btrfs: fix deletion of a range spanning parts two RAID stripe extents
Browse files Browse the repository at this point in the history
When a user requests the deletion of a range that spans multiple stripe
extents and btrfs_search_slot() returns us the second RAID stripe extent,
we need to pick the previous item and truncate it, if there's still a
range to delete left, move on to the next item.

The following diagram illustrates the operation:

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

While at it, comment the trivial case of a whole item delete as well.

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 50cae2c commit 7664311
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions fs/btrfs/raid-stripe-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,37 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
found_end = found_start + key.offset;
ret = 0;

/*
* The stripe extent starts before the range we want to delete,
* but the range spans more than one stripe extent:
*
* |--- RAID Stripe Extent ---||--- RAID Stripe Extent ---|
* |--- keep ---|--- drop ---|
*
* This means we have to get the previous item, truncate its
* length and then restart the search.
*/
if (found_start > start) {
if (slot == 0) {
ret = btrfs_previous_item(stripe_root, path, start,
BTRFS_RAID_STRIPE_KEY);
if (ret) {
if (ret > 0)
ret = -ENOENT;
break;
}
} else {
path->slots[0]--;
}

leaf = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(leaf, &key, slot);
found_start = key.objectid;
found_end = found_start + key.offset;
ASSERT(found_start <= start);
}

if (key.type != BTRFS_RAID_STRIPE_KEY)
break;

Expand Down Expand Up @@ -152,6 +183,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
break;
}

/* Finally we can delete the whole item, no more special cases. */
ret = btrfs_del_item(trans, stripe_root, path);
if (ret)
break;
Expand Down

0 comments on commit 7664311

Please sign in to comment.