summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorrobbieko <robbieko@synology.com>2026-04-13 14:52:36 +0800
committerDavid Sterba <dsterba@suse.com>2026-04-21 04:02:34 +0200
commitfe0cdfd7118d8b40a21bfac221bb4982c5e10e10 (patch)
treeec9642f0a25558a4dc2a963d7e97985bf14046a5 /fs
parent653361585d251fbca0e19ac58b04ba95dd01e378 (diff)
btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer
In the 'punch a hole' case of btrfs_delete_raid_extent(), btrfs_duplicate_item() can return -EAGAIN when the leaf needs to be split and the path becomes invalid. The old code treats any error as fatal and breaks out of the loop. Additionally, btrfs_duplicate_item() may trigger setup_leaf_for_split() which can reallocate the leaf node. The code continues using the old leaf pointer, leading to use-after-free or stale data access. Fix both issues by: - Handling -EAGAIN specifically: release the path and retry the loop. - Refreshing leaf = path->nodes[0] after successful duplication. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: robbieko <robbieko@synology.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/raid-stripe-tree.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index d454894b9e66..2e0d2f83c651 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -194,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "right" item. */
ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey);
+ if (ret == -EAGAIN) {
+ btrfs_release_path(path);
+ continue;
+ }
if (ret)
break;
+ /*
+ * btrfs_duplicate_item() may have triggered a leaf
+ * split via setup_leaf_for_split(), so we must refresh
+ * our leaf pointer from the path.
+ */
+ leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, path->slots[0]);
extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_stripe_extent);