Commit fe0cdfd7 authored by robbieko's avatar robbieko Committed by David Sterba
Browse files

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: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarrobbieko <robbieko@synology.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 65336158
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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);