]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: fix raid stripe search missing entries at leaf boundaries
authorrobbieko <robbieko@synology.com>
Mon, 13 Apr 2026 06:52:33 +0000 (14:52 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 21 Apr 2026 02:02:21 +0000 (04:02 +0200)
In btrfs_delete_raid_extent(), the search key uses offset=0. When the
target stripe entry is the first item on a leaf, btrfs_search_slot()
may land on the previous leaf and decrementing the slot from nritems
still points to the wrong entry, causing the stripe extent to be
silently missed.

Fix this by searching with offset=(u64)-1 instead. Since no real stripe
entry has this offset, btrfs_search_slot() always returns 1 with the
slot pointing past the last matching objectid entry. Then unconditionally
decrement the slot with a proper slots[0]==0 early-exit check to handle
the case where no matching entry exists.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/raid-stripe-tree.c

index ac8cec3ce6d34f5895ea27648bc36aeb3a22e5c2..4937b08da9deacf92cf23720a0b9f5abb74810f3 100644 (file)
@@ -98,14 +98,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
        while (1) {
                key.objectid = start;
                key.type = BTRFS_RAID_STRIPE_KEY;
-               key.offset = 0;
+               key.offset = (u64)-1;
 
                ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1);
                if (ret < 0)
                        break;
 
-               if (path->slots[0] == btrfs_header_nritems(path->nodes[0]))
-                       path->slots[0]--;
+               /*
+                * Search with offset=(u64)-1 ensures we land on the correct
+                * leaf even when the target entry is the first item on a leaf.
+                * Since no real entry has offset=(u64)-1, ret is always 1 and
+                * slot points past the last entry with objectid==start (or
+                * past the end of the leaf if that entry is the last item).
+                * Back up one slot to find the actual entry.
+                */
+               if (path->slots[0] == 0) {
+                       /* No entry with objectid <= start exists. */
+                       ret = 0;
+                       break;
+               }
+               path->slots[0]--;
 
                leaf = path->nodes[0];
                slot = path->slots[0];