Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

robbieko and committed by
David Sterba
fe0cdfd7 65336158

+10
+10
fs/btrfs/raid-stripe-tree.c
··· 194 194 195 195 /* The "right" item. */ 196 196 ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); 197 + if (ret == -EAGAIN) { 198 + btrfs_release_path(path); 199 + continue; 200 + } 197 201 if (ret) 198 202 break; 199 203 204 + /* 205 + * btrfs_duplicate_item() may have triggered a leaf 206 + * split via setup_leaf_for_split(), so we must refresh 207 + * our leaf pointer from the path. 208 + */ 209 + leaf = path->nodes[0]; 200 210 item_size = btrfs_item_size(leaf, path->slots[0]); 201 211 extent = btrfs_item_ptr(leaf, path->slots[0], 202 212 struct btrfs_stripe_extent);