mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-17 21:17:25 -04:00
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>
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user